[vala/wip/dbusgen: 1/6] first commit of dbusgen



commit db3313487082c4b41642fda5526d289407475abb
Author: Chris Daley <chebizarro gmail com>
Date:   Mon Nov 20 13:49:16 2017 -0800

    first commit of dbusgen

 dbusgen/.gitignore                  |    1 +
 dbusgen/Makefile.am                 |  118 ++
 dbusgen/Makefile.dbusgen            |   61 +
 dbusgen/dbusgen.m4                  |  101 ++
 dbusgen/dbusgen.pc.in               |   15 +
 dbusgen/vala-dbus-binding-tool.vala | 1153 +++++++++++++
 dbusgen/valadbusgen.vala            |  176 ++
 dbusgen/valadbusparser.vala         | 3188 +++++++++++++++++++++++++++++++++++
 dbusgen/valavapicheck.vala          |  180 ++
 9 files changed, 4993 insertions(+), 0 deletions(-)
---
diff --git a/dbusgen/.gitignore b/dbusgen/.gitignore
new file mode 100644
index 0000000..e932362
--- /dev/null
+++ b/dbusgen/.gitignore
@@ -0,0 +1 @@
+dbusgen
diff --git a/dbusgen/Makefile.am b/dbusgen/Makefile.am
new file mode 100644
index 0000000..ece0c6c
--- /dev/null
+++ b/dbusgen/Makefile.am
@@ -0,0 +1,118 @@
+include $(top_srcdir)/Makefile.common
+
+NULL =
+
+SUBDIRS = \
+       vala-gen-introspect \
+       $(NULL)
+
+AM_CPPFLAGS = \
+       $(GLIB_CFLAGS) \
+       -I$(top_srcdir)/gee \
+       -I$(top_srcdir)/ccode \
+       -I$(top_srcdir)/vala \
+       -I$(top_srcdir)/gobject-introspection \
+       $(NULL)
+
+bin_PROGRAMS = \
+       vapigen \
+       vapicheck \
+       $(NULL)
+
+BUILT_SOURCES = vapigen.vala.stamp vapicheck.vala.stamp
+
+vapigen_VALASOURCES = \
+       valagidlparser.vala \
+       valavapigen.vala \
+       $(NULL)
+
+vapigen_SOURCES = \
+       vapigen.vala.stamp \
+       $(vapigen_VALASOURCES:.vala=.c) \
+       $(NULL)
+
+vapicheck_VALASOURCES = \
+       valavapicheck.vala \
+       $(NULL)
+
+vapicheck_SOURCES = \
+       vapicheck.vala.stamp \
+       $(vapicheck_VALASOURCES:.vala=.c) \
+       $(NULL)
+
+vapigen.vala.stamp: $(vapigen_VALASOURCES)
+       $(VALA_V)$(VALAC) \
+               $(VALAFLAGS) \
+               -C \
+               --vapidir $(top_srcdir)/vapi \
+               --vapidir $(top_srcdir)/gee --pkg gee \
+               --vapidir $(top_srcdir)/vala --pkg vala \
+               --vapidir $(top_srcdir)/gobject-introspection --pkg gidl \
+               --pkg config \
+               $^
+       @touch $@
+
+vapicheck.vala.stamp: $(vapicheck_VALASOURCES)
+       $(VALA_V)$(VALAC) \
+               $(VALAFLAGS) \
+               -C \
+               --vapidir $(top_srcdir)/vapi \
+               --vapidir $(top_srcdir)/gee --pkg gee \
+               --vapidir $(top_srcdir)/vala --pkg vala \
+               --vapidir $(top_srcdir)/gobject-introspection --pkg gidl \
+               --pkg config \
+               $^
+       @touch $@
+
+vapigen_LDADD = \
+       $(GLIB_LIBS) \
+       $(top_builddir)/vala/libvala@PACKAGE_SUFFIX@.la \
+       $(top_builddir)/gobject-introspection/libgidl.la \
+       $(NULL)
+
+vapicheck_LDADD = \
+       $(GLIB_LIBS) \
+       $(top_builddir)/vala/libvala@PACKAGE_SUFFIX@.la \
+       $(top_builddir)/gobject-introspection/libgidl.la \
+       $(NULL)
+
+if ENABLE_UNVERSIONED
+makedir = $(datadir)/vala
+make_DATA = Makefile.vapigen
+
+aclocaldir = $(datadir)/aclocal
+aclocal_DATA = vapigen.m4
+endif
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = vapigen@PACKAGE_SUFFIX@.pc
+
+vapigen@PACKAGE_SUFFIX@.pc: vapigen.pc
+       cp $< $@
+
+EXTRA_DIST = \
+       $(vapigen_VALASOURCES) \
+       $(vapicheck_VALASOURCES) \
+       Makefile.vapigen \
+       vapigen.m4 \
+       vapigen.vala.stamp \
+       vapicheck.vala.stamp \
+       $(NULL)
+
+CLEANFILES = \
+       vapigen@PACKAGE_SUFFIX@.pc
+       $(NULL)
+
+if ENABLE_UNVERSIONED
+install-exec-hook:
+       cd $(DESTDIR)$(bindir) && $(LN_S) -f vapigen@PACKAGE_SUFFIX@$(EXEEXT) vapigen$(EXEEXT)
+       cd $(DESTDIR)$(bindir) && $(LN_S) -f vapicheck@PACKAGE_SUFFIX@$(EXEEXT) vapicheck$(EXEEXT)
+
+install-data-hook:
+       cd $(DESTDIR)$(pkgconfigdir) && $(LN_S) -f vapigen@PACKAGE_SUFFIX@.pc vapigen.pc
+endif
+
+MAINTAINERCLEANFILES = \
+       $(vapigen_VALASOURCES:.vala=.c) \
+       $(vapicheck_VALASOURCES:.vala=.c) \
+       $(NULL)
diff --git a/dbusgen/Makefile.dbusgen b/dbusgen/Makefile.dbusgen
new file mode 100644
index 0000000..03fb2e4
--- /dev/null
+++ b/dbusgen/Makefile.dbusgen
@@ -0,0 +1,61 @@
+# Makefile for Vala API Generator (vapigen)
+# Written by Evan Nemerson
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+# See http://live.gnome.org/Vala/UpstreamGuide for detailed documentation
+#
+# Variables:
+#
+#   VAPIGEN_FILES
+#
+#     VAPIs to create
+#
+#   *_DEPS / VAPIGEN_DEPS
+#
+#       The dependencies. Generally the pkg-config names.
+#
+#   *_METADATADIRS / VAPIGEN_METADATADIRS
+#
+#       Directory containing the metadata.
+#
+#   *_VAPIDIRS / VAPIGEN_VAPIDIRS
+#
+#       Additional location(s) to search for VAPI dependencies.
+#
+#   *_GIRDIRS / VAPIGEN_GIRDIRS
+#
+#       Additional location(s) to search for GIR dependencies.
+#
+#   *_FILES
+#
+#       The files which should be used to generate the VAPI.
+
+_vapigen_silent_prefix = $(_vapigen_silent_prefix_$(V))
+_vapigen_silent_prefix_ = $(_vapigen_silent_prefix_$(AM_DEFAULT_VERBOSITY))
+_vapigen_silent_prefix_0 = @echo " VAPIGEN $(1)";
+_vapigen_silent_opts = $(_vapigen_silent_opts_$(V))
+_vapigen_silent_opts_ = $(_vapigen_silent_opts_$(AM_DEFAULT_VERBOSITY))
+_vapigen_silent_opts_0 = --quiet
+
+$(if $(VAPIGEN),,$(error You must define VAPIGEN))
+
+_vapi_name = $(subst /,_,$(subst -,_,$(subst .,_,$(1))))
+
+define vapigen
+$(1): $$($(_vapi_name)_GIR)
+       $(_vapigen_silent_prefix) $(VAPIGEN) $(_vapigen_silent_opts) \
+         --library $(1:.vapi=) \
+         $(foreach _vapi_metadatadir_name,$(if 
$($(_vapi_name)_METADATADIRS),$($(_vapi_name)_METADATADIRS),$(VAPIGEN_METADATADIRS)),--metadatadir 
$(_vapi_metadatadir_name)) \
+         $(foreach _vapi_dir_name,$(if 
$($(_vapi_name)_VAPIDIRS),$($(_vapi_name)_VAPIDIRS),$(VAPIGEN_VAPIDIRS)),--vapidir $(_vapi_dir_name)) \
+         $(foreach _gir_dir_name,$(if 
$($(_vapi_name)_GIRDIRS),$($(_vapi_name)_GIRDIRS),$(VAPIGEN_GIRDIRS)),--girdir $(_gir_dir_name)) \
+         $(foreach _vapi_dep_name,$(if $($(_vapi_name)_DEPS),$($(_vapi_name)_DEPS),$(VAPIGEN_DEPS)),--pkg 
$(_vapi_dep_name)) \
+         $$($(_vapi_name)_FILES)
+endef
+
+$(foreach vapi,$(VAPIGEN_VAPIS),$(eval $(call vapigen,$(vapi))))
diff --git a/dbusgen/dbusgen.m4 b/dbusgen/dbusgen.m4
new file mode 100644
index 0000000..2c435e7
--- /dev/null
+++ b/dbusgen/dbusgen.m4
@@ -0,0 +1,101 @@
+dnl vapigen.m4
+dnl
+dnl Copyright 2012 Evan Nemerson
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+
+# VAPIGEN_CHECK([VERSION], [API_VERSION], [FOUND_INTROSPECTION], [DEFAULT])
+# --------------------------------------
+# Check vapigen existence and version
+#
+# See http://live.gnome.org/Vala/UpstreamGuide for detailed documentation
+AC_DEFUN([VAPIGEN_CHECK],
+[
+  AS_IF([test "x$3" != "xyes"], [
+      m4_provide_if([GOBJECT_INTROSPECTION_CHECK], [], [
+          m4_provide_if([GOBJECT_INTROSPECTION_REQUIRE], [], [
+              AC_MSG_ERROR([[You must call GOBJECT_INTROSPECTION_CHECK or GOBJECT_INTROSPECTION_REQUIRE 
before using VAPIGEN_CHECK unless using the FOUND_INTROSPECTION argument is "yes"]])
+            ])
+        ])
+    ])
+
+  AC_ARG_ENABLE([vala],
+    [AS_HELP_STRING([--enable-vala[=@<:@no/auto/yes@:>@]],[build Vala bindings 
@<:@default=]ifelse($4,,auto,$4)[@:>@])],,[
+      AS_IF([test "x$4" = "x"], [
+          enable_vala=auto
+        ], [
+          enable_vala=$4
+        ])
+    ])
+
+  AS_CASE([$enable_vala], [no], [enable_vala=no],
+      [yes], [
+        AS_IF([test "x$3" != "xyes" -a "x$found_introspection" != "xyes"], [
+            AC_MSG_ERROR([Vala bindings require GObject Introspection])
+          ])
+      ], [auto], [
+        AS_IF([test "x$3" != "xyes" -a "x$found_introspection" != "xyes"], [
+            enable_vala=no
+          ])
+      ], [
+        AC_MSG_ERROR([Invalid argument passed to --enable-vala, should be one of @<:@no/auto/yes@:>@])
+      ])
+
+  AS_IF([test "x$2" = "x"], [
+      vapigen_pkg_name=vapigen
+    ], [
+      vapigen_pkg_name=vapigen-$2
+    ])
+  AS_IF([test "x$1" = "x"], [
+      vapigen_pkg="$vapigen_pkg_name"
+    ], [
+      vapigen_pkg="$vapigen_pkg_name >= $1"
+    ])
+
+  PKG_PROG_PKG_CONFIG
+
+  PKG_CHECK_EXISTS([$vapigen_pkg], [
+      AS_IF([test "$enable_vala" = "auto"], [
+          enable_vala=yes
+        ])
+    ], [
+      AS_CASE([$enable_vala], [yes], [
+          AC_MSG_ERROR([$vapigen_pkg not found])
+        ], [auto], [
+          enable_vala=no
+        ])
+    ])
+
+  AC_MSG_CHECKING([for vapigen])
+
+  AS_CASE([$enable_vala],
+    [yes], [
+      VAPIGEN=`$PKG_CONFIG --variable=vapigen $vapigen_pkg_name`
+      VAPIGEN_MAKEFILE=`$PKG_CONFIG --variable=datadir $vapigen_pkg_name`/vala/Makefile.vapigen
+      AS_IF([test "x$2" = "x"], [
+          VAPIGEN_VAPIDIR=`$PKG_CONFIG --variable=vapidir $vapigen_pkg_name`
+        ], [
+          VAPIGEN_VAPIDIR=`$PKG_CONFIG --variable=vapidir_versioned $vapigen_pkg_name`
+        ])
+    ])
+
+  AC_MSG_RESULT([$enable_vala])
+
+  AC_SUBST([VAPIGEN])
+  AC_SUBST([VAPIGEN_VAPIDIR])
+  AC_SUBST([VAPIGEN_MAKEFILE])
+
+  AM_CONDITIONAL(ENABLE_VAPIGEN, test "x$enable_vala" = "xyes")
+])
diff --git a/dbusgen/dbusgen.pc.in b/dbusgen/dbusgen.pc.in
new file mode 100644
index 0000000..ecd54ce
--- /dev/null
+++ b/dbusgen/dbusgen.pc.in
@@ -0,0 +1,15 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+bindir=@bindir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+includedir=@includedir@
+
+vapigen=${bindir}/vapigen@PACKAGE_SUFFIX@
+vapidir=${datadir}/vala/vapi
+vapidir_versioned=${datadir}/vala@PACKAGE_SUFFIX@/vapi
+
+Name: vapigen
+Description: Vala API Generator
+Version: @VERSION@
diff --git a/dbusgen/vala-dbus-binding-tool.vala b/dbusgen/vala-dbus-binding-tool.vala
new file mode 100644
index 0000000..8a560db
--- /dev/null
+++ b/dbusgen/vala-dbus-binding-tool.vala
@@ -0,0 +1,1153 @@
+/*
+ * vala-dbus-binding-tool.vala
+ *
+ * (C) 2009 by Didier "Ptitjes" <ptitjes free fr>
+ * (C) 2009-2015 the freesmartphone.org team <fso openphoenux org>
+ *
+ * GPLv3
+ */
+using GLib;
+using Xml;
+using Gee;
+
+public errordomain GeneratorError {
+       FILE_NOT_FOUND,
+       CANT_CREATE_FILE,
+       UNKNOWN_DBUS_TYPE
+}
+
+public enum Synchrony {
+       AUTO,
+       FORCE_SYNC,
+       FORCE_ASYNC
+}
+
+internal class GeneratedNamespace {
+       public GeneratedNamespace parent;
+       public string name;
+       public Gee.Map<string, Xml.Node*> members = new Gee.HashMap<string, Xml.Node*>();
+       public Gee.Map<string, GeneratedNamespace> namespaces = new Gee.HashMap<string, GeneratedNamespace>();
+}
+
+public class BindingGenerator : Object {
+
+       private static Set<string> registered_names = new HashSet<string>();
+       private static int verbosity;
+       private static int errors;
+       private static bool synced;
+
+       static construct {
+               registered_names.add("using");
+               registered_names.add("namespace");
+               registered_names.add("public");
+               registered_names.add("private");
+               registered_names.add("register");
+               registered_names.add("internal");
+               registered_names.add("errordomain");
+               registered_names.add("class");
+               registered_names.add("struct");
+               registered_names.add("new");
+               registered_names.add("for");
+               registered_names.add("while");
+               registered_names.add("foreach");
+               registered_names.add("switch");
+               registered_names.add("catch");
+               registered_names.add("case");
+               registered_names.add("static");
+               registered_names.add("unowned");
+               registered_names.add("weak");
+               registered_names.add("message");
+               registered_names.add("get_type");
+               registered_names.add("dispose");
+               registered_names.add("result");
+       }
+
+       public static void INFO(string msg) {
+               if (verbosity >= 1)
+                       stdout.printf(@"[INFO]  $msg\n");
+       }
+
+       public static void DEBUG(string msg) {
+               if (verbosity >= 2)
+                       stdout.printf(@"[DEBUG] $msg\n");
+       }
+
+       public static void WARN(string msg) {
+               stderr.printf(@"[WARN]  $msg\n");
+       }
+
+       public static void ERROR(string msg) {
+               stderr.printf(@"[ERROR] $msg\n");
+               errors++;
+       }
+
+       public static int main(string[] args) {
+               //FIXME: Convert to OptionEntry
+               string[] split_name = args[0].split("/");
+               string program_name = split_name[split_name.length - 1];
+               string command = string.joinv(" ", args);
+
+               string api_path = null;
+               string output_directory = null;
+               uint dbus_timeout = 120000;
+               synced = true;
+
+               Map<string,string> namespace_renaming = new HashMap<string,string>();
+
+               for (int i = 1; i < args.length; i++) {
+                       string arg = args[i];
+
+                       string[] split_arg = arg.split("=");
+                       switch (split_arg[0]) {
+                       case "-h":
+                       case "--help":
+                               show_usage(program_name);
+                               return 0;
+                       case "-v":
+                               verbosity++;
+                               break;
+                       case "--version":
+                               show_version();
+                               return 0;
+                       case "--api-path":
+                               api_path = split_arg[1];
+                               break;
+                       case "-d":
+                       case "--directory":
+                               output_directory = split_arg[1];
+                               break;
+                       case "--strip-namespace":
+                               namespace_renaming.set(split_arg[1], "");
+                               break;
+                       case "--rename-namespace":
+                               string[] ns_split = split_arg[1].split(":");
+                               namespace_renaming.set(ns_split[0], ns_split[1]);
+                               break;
+                       case "--dbus-timeout":
+                               dbus_timeout = int.parse( split_arg[1] );
+                               break;
+                       case "--no-synced":
+                               synced = false;
+                               break;
+                       default:
+                               stdout.printf("%s: Unknown option %s\n", program_name, arg);
+                               show_usage(program_name);
+                               return 1;
+                       }
+               }
+
+               if (api_path == null)
+                       api_path = "./";
+               if (output_directory == null)
+                       output_directory = ".";
+
+               try {
+                       generate(api_path, output_directory, namespace_renaming, command, dbus_timeout);
+               } catch (GLib.FileError ex) {
+                       ERROR(ex.message);
+                       return 1;
+               } catch (GeneratorError ex) {
+                       ERROR(ex.message);
+                       return 1;
+               }
+
+               if (errors > 0) {
+                       stdout.printf( @"\n$errors errors detected in API files. The generated files will not 
be usable.\n" );
+                       return 1;
+               }
+               return 0;
+       }
+
+       private static void show_version() {
+               stdout.printf(@"Vala D-Bus Binding Tool $(Config.PACKAGE_VERSION)\n");
+               stdout.printf("Written by Didier \"Ptitjes\" and the freesmartphone.org team\n");
+               stdout.printf("This is free software; see the source for copying conditions.\n");
+               stdout.printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 
PURPOSE.\n");
+       }
+
+       private static void show_usage(string program_name) {
+               stdout.printf("Usage:\n");
+               stdout.printf("  %s [-v] [--version] [--help]\n", program_name);
+               stdout.printf("  %s [--api-path=PATH] [--no-synced] [--dbus-timeout=TIMEOUT] 
[--directory=DIR] [--strip-namespace=NS]* [--rename-namespace=OLD_NS:NEW_NS]*\n", program_name);
+       }
+
+       public static void generate(string api_path, string output_directory,
+                       Map<string,string> namespace_renaming, string command, uint dbus_timeout)
+                       throws GeneratorError, GLib.FileError {
+
+               Parser.init();
+
+               BindingGenerator generator = new BindingGenerator(output_directory, namespace_renaming, 
command, dbus_timeout);
+               generator.generate_bindings(api_path);
+
+               Parser.cleanup();
+       }
+
+       private BindingGenerator(string output_directory, Map<string,string> namespace_renaming, string 
command, uint dbus_timeout) {
+               this.output_directory = output_directory;
+               this.namespace_renaming = namespace_renaming;
+               this.command = command;
+               this.dbus_timeout = dbus_timeout;
+       }
+
+       private string output_directory;
+       private Map<string,string> namespace_renaming;
+       private string command;
+       private uint dbus_timeout;
+       private bool inner_interface_strategy_concat = true;
+
+       private const string FSO_NAMESPACE = "http://www.freesmartphone.org/schemas/DBusSpecExtension";;
+
+       private const string INTERFACE_ELTNAME = "interface";
+       private const string METHOD_ELTNAME = "method";
+       private const string SIGNAL_ELTNAME = "signal";
+       private const string PROPERTY_ELTNAME = "property";
+       private const string ARG_ELTNAME = "arg";
+       private const string NAME_ATTRNAME = "name";
+       private const string TYPE_ATTRNAME = "type";
+       private const string DIRECTION_ATTRNAME = "direction";
+       private const string REPLACED_BY_ATTRNAME = "replaced-by";
+       private const string IN_ATTRVALUE = "in";
+       private const string OUT_ATTRVALUE = "out";
+       private const string ENUMERATION_ELTNAME = "enumeration";
+       private const string MEMBER_ELTNAME = "member";
+       private const string VALUE_ATTRNAME = "value";
+       private const string ERRORDOMAIN_ELTNAME = "errordomain";
+       private const string ERROR_ELTNAME = "error";
+       private const string NO_CONTAINER_ATTRNAME = "no-container";
+       private const string THROWS_ELTNAME = "throws";
+       private const string STRUCT_ELTNAME = "struct";
+       private const string FIELD_ELTNAME = "field";
+       private const string ANNOTATION_ELTNAME = "annotation";
+       private const string DEPRECATED_ELTNAME = "deprecated";
+
+       private void generate_bindings(string api_path)
+                       throws GeneratorError, GLib.FileError {
+
+               if (api_path.has_suffix(".xml")) {
+                       add_api_file(api_path);
+               } else {
+                       GLib.Dir dir = GLib.Dir.open(api_path);
+                       string name;
+                       while ((name = dir.read_name()) != null) {
+                               if (name.has_suffix(".xml")) {
+                                       add_api_file(Path.build_filename(api_path, name));
+                               }
+                       }
+               }
+
+               index_names(root_namespace);
+               generate_namespace(root_namespace);
+       }
+
+       private void add_api_file(string api_file) throws GeneratorError {
+               INFO(@"Adding API file $api_file");
+               // Parse the API document from path
+               Xml.Doc* api_doc = Parser.parse_file(api_file);
+               if (api_doc == null) {
+                       throw new GeneratorError.FILE_NOT_FOUND(api_file);
+               }
+
+               api_docs.add(api_doc);
+
+               preprocess_binding_names(api_doc);
+       }
+
+       private FileStream output;
+
+       private void create_binding_file(string name) throws GeneratorError {
+               output = FileStream.open(name, "w");
+               if (output == null) {
+                       throw new GeneratorError.CANT_CREATE_FILE(name);
+               }
+
+               output.printf(@"/* Generated by vala-dbus-binding-tool $(Config.PACKAGE_VERSION). Do not 
modify! */\n");
+               output.printf(@"/* Generated with: $command */\n");
+               output.printf("using GLib;\n");
+       }
+
+       private Gee.List<Xml.Doc*> api_docs = new Gee.ArrayList<Xml.Doc*>();
+
+       private void preprocess_binding_names(Xml.Doc* api_doc) {
+               for (Xml.Node* iter = api_doc->get_root_element()->children; iter != null; iter = iter->next) 
{
+                       //FIXME: Use $(iter->type) when enum to_string works
+                       DEBUG(@"   Processing $(iter->name) as type %d".printf(iter->type));
+                       if (iter->type != ElementType.ELEMENT_NODE) {
+                               DEBUG(@"      not a node; continuing");
+                               continue;
+                       }
+
+                       if (iter->name != INTERFACE_ELTNAME
+                               && iter->name != ENUMERATION_ELTNAME
+                               && iter->name != ERRORDOMAIN_ELTNAME
+                               && iter->name != STRUCT_ELTNAME) {
+                               DEBUG(@"      not interface or enumeration or errordomain or struct; 
continuing");
+                               continue;
+                       }
+
+                       string no_error_container_string = iter->get_ns_prop(NO_CONTAINER_ATTRNAME, 
FSO_NAMESPACE);
+                       bool no_error_container = (no_error_container_string != null && 
no_error_container_string == "true");
+
+                       string dbus_interface_name = iter->get_prop(NAME_ATTRNAME);
+                       string[] split_name = dbus_interface_name.split(".");
+                       string short_name;
+                       int last_part;
+                       if (iter->name == ERRORDOMAIN_ELTNAME && no_error_container) {
+                               short_name = "Error";
+                               last_part = split_name.length;
+                       } else {
+                               short_name = split_name[split_name.length - 1];
+                               last_part = split_name.length - 1;
+                       }
+
+                       // Removing stripped root namespaces
+                       int i = 0;
+                       for (; i < last_part; i++) {
+                               string part = split_name[i];
+                               if (namespace_renaming.get(part) != "") break;
+                       }
+
+                       // Traversing inner namespaces
+                       GeneratedNamespace ns = root_namespace;
+                       for (; i < last_part; i++) {
+                               string part = split_name[i];
+
+                               if (namespace_renaming.has_key(part) && namespace_renaming.get(part) != "") {
+                                       part = namespace_renaming.get(part);
+                               }
+
+                               if (ns.members.has_key(part) && inner_interface_strategy_concat) {
+                                       if (ns.namespaces.has_key(part)) {
+                                               GeneratedNamespace child = ns.namespaces.get(part);
+                                               foreach (string interf_name in child.members.keys) {
+                                                       Xml.Node* interf = child.members.get(interf_name);
+                                                       ns.members.set(part + interf_name, interf);
+                                               }
+                                               ns.namespaces.unset(part);
+                                               child.parent = null;
+                                       }
+
+                                       break;
+                               }
+
+                               GeneratedNamespace child = null;
+                               if (ns.namespaces.has_key(part)) {
+                                       child = ns.namespaces.get(part);
+                               } else {
+                                       child = new GeneratedNamespace();
+                                       child.parent = ns;
+                                       child.name = part;
+                                       ns.namespaces.set(part, child);
+                               }
+
+                               if (ns.members.has_key(part)) {
+                                               child.members.set(part, ns.members.get(part));
+                                               ns.members.unset(part);
+                               }
+
+                               ns = child;
+                       }
+
+                       string interface_name = null;
+                       if (inner_interface_strategy_concat) {
+                               StringBuilder name_builder = new StringBuilder();
+                               // Concatenating last inner namespaces
+                               for (; i < last_part; i++) {
+                                       name_builder.append(split_name[i]);
+                               }
+                               name_builder.append(short_name);
+                               interface_name = name_builder.str;
+
+                               if (ns.namespaces.has_key(short_name)) {
+                                       GeneratedNamespace child = ns.namespaces.get(short_name);
+                                       foreach (string interf_name in child.members.keys) {
+                                               Xml.Node* interf = child.members.get(interf_name);
+                                               ns.members.set(short_name + interf_name, interf);
+                                       }
+                                       ns.namespaces.unset(short_name);
+                                       child.parent = null;
+                               }
+                       } else {
+                               if (ns.namespaces.has_key(short_name)) {
+                                       ns = ns.namespaces.get(short_name);
+                               }
+                               interface_name = short_name;
+                       }
+
+                       if (!ns.members.has_key(interface_name)) {
+                               ns.members.set(interface_name, iter);
+                       } else {
+                               Xml.Node* iter2 = ns.members.get(interface_name);
+                               var name = iter2->get_prop(NAME_ATTRNAME);
+                               ERROR(@"$interface_name has been added already as namespace $name");
+                       }
+               }
+       }
+
+       private void index_names(GeneratedNamespace ns) {
+               if (ns.members.size > 0) {
+                       string namespace_name = string.joinv(".", get_namespace_path(ns));
+
+                       foreach (string name in ns.members.keys) {
+                               Xml.Node* api = ns.members.get(name);
+                               string dbus_name = api->get_prop(NAME_ATTRNAME);
+                               if (api->name == ERRORDOMAIN_ELTNAME) {
+                                       INFO(@"Registering new errordomain $dbus_name");
+                                       error_name_index.set(dbus_name, namespace_name + "." + name);
+                               } else {
+                                       name_index.set(dbus_name, namespace_name + "." + name);
+                               }
+                       }
+               }
+
+               foreach (string name in ns.namespaces.keys) {
+                       GeneratedNamespace child = ns.namespaces.get(name);
+
+                       index_names(child);
+               }
+       }
+
+       private string[] get_namespace_path(GeneratedNamespace ns) {
+               string[] reversed_namespace_names = new string[0];
+               GeneratedNamespace a_namespace = ns;
+               while (a_namespace.name != null) {
+                       reversed_namespace_names += a_namespace.name;
+                       a_namespace = a_namespace.parent;
+               }
+
+               string[] namespace_names = new string[0];
+               for (int i = reversed_namespace_names.length - 1; i >= 0; i--) {
+                       namespace_names += reversed_namespace_names[i];
+               }
+
+               return namespace_names;
+       }
+
+       private GeneratedNamespace root_namespace = new GeneratedNamespace();
+
+       private Map<string, string> name_index = new HashMap<string, string>();
+       private Map<string, string> error_name_index = new HashMap<string, string>();
+
+       private void generate_namespace(GeneratedNamespace ns)
+                       throws GeneratorError {
+               if (ns.members.size > 0) {
+                       string[] namespace_names = get_namespace_path(ns);
+
+                       create_binding_file(output_directory + "/" + string.joinv("-", 
namespace_names).down() + ".vala");
+
+                       foreach (string name in namespace_names) {
+                               output.printf("\n");
+                               output.printf("%snamespace %s {\n", get_indent(), name);
+                               update_indent(+1);
+                       }
+
+                       foreach (string name in ns.members.keys) {
+                               Xml.Node* api = ns.members.get(name);
+
+                               switch (api->name) {
+                               case INTERFACE_ELTNAME:
+                                       generate_interface(name, api, Synchrony.AUTO);
+                                       generate_proxy_getter(api, name);
+                                       if ( synced )
+                                               generate_interface(name, api, Synchrony.FORCE_SYNC);
+                                               generate_proxy_getter(api, name, Synchrony.FORCE_SYNC);
+                                       break;
+                               case ENUMERATION_ELTNAME:
+                                       generate_enumeration(name, api);
+                                       break;
+                               case ERRORDOMAIN_ELTNAME:
+                                       generate_errordomain(name, api);
+                                       break;
+                               case STRUCT_ELTNAME:
+                                       generate_explicit_struct(name, api);
+                                       break;
+                               }
+                       }
+
+                       foreach (string name in namespace_names) {
+                               update_indent(-1);
+                               output.printf("%s}\n", get_indent());
+                       }
+
+                       output = null;
+               }
+
+               foreach (string name in ns.namespaces.keys) {
+                       GeneratedNamespace child = ns.namespaces.get(name);
+
+                       generate_namespace(child);
+               }
+       }
+
+       private Gee.Map<string, string> structs_to_generate = new Gee.HashMap<string, string>();
+
+       private void generate_interface(string interface_name, Xml.Node* node, Synchrony synchrony = 
Synchrony.AUTO)
+                       throws GeneratorError {
+               string dbus_name = node->get_prop(NAME_ATTRNAME);
+               string namespace_name = get_namespace_name(interface_name);
+
+               assert( synchrony != Synchrony.FORCE_ASYNC ); // not supported yet, maybe never
+
+               var iface_name = ( synchrony == Synchrony.FORCE_SYNC ) ? interface_name + "Sync" : 
interface_name;
+
+               INFO(@"Generating interface $dbus_name");
+
+               output.printf("\n");
+               output.printf("%s[DBus (name = \"%s\", timeout = %u)]\n", get_indent(), dbus_name, 
dbus_timeout);
+               output.printf("%spublic interface %s : GLib.Object {\n", get_indent(), iface_name);
+               update_indent(+1);
+
+               generate_members(node, iface_name, get_namespace_name(dbus_name), synchrony);
+
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+
+               while (structs_to_generate.size != 0) {
+                       Gee.Map<string, string> structs_to_generate_now = new Gee.HashMap<string, string>();
+                       structs_to_generate_now.set_all(structs_to_generate);
+                       foreach (var entry in structs_to_generate_now.entries) {
+                               generate_struct(entry.key, entry.value, namespace_name);
+                       }
+                       structs_to_generate.unset_all(structs_to_generate_now);
+               }
+       }
+
+       private void generate_enumeration(string enumeration_name, Xml.Node* node) throws GeneratorError {
+               string dbus_name = node->get_prop(NAME_ATTRNAME);
+               string type = node->get_prop(TYPE_ATTRNAME);
+               bool string_enum = type == "s";
+
+               INFO(@"Generating enumeration $type for $dbus_name");
+
+               output.printf("\n");
+               output.printf("%s[DBus%s]\n", get_indent(), string_enum ? " (use_string_marshalling = true)" 
: "");
+               output.printf("%spublic enum %s {\n", get_indent(), enumeration_name);
+               update_indent(+1);
+
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case MEMBER_ELTNAME:
+                               string member_name = normalized_to_upper_case(iter->get_prop(NAME_ATTRNAME));
+                               string member_value = iter->get_prop(VALUE_ATTRNAME);
+                               if (string_enum) {
+                                       output.printf("%s[DBus (value=\"%s\")]\n", get_indent(), 
member_value);
+                               }
+                               output.printf("%s%s%s%s\n", get_indent(), member_name, string_enum ? "" : " = 
%s".printf(member_value), iter->next == null ? "" : ",");
+                               break;
+                       }
+               }
+
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+       }
+
+       private void generate_errordomain(string errordomain_name, Xml.Node* node)
+                       throws GeneratorError {
+               string dbus_name = node->get_prop(NAME_ATTRNAME);
+
+               INFO(@"Generating errordomain $errordomain_name for $dbus_name");
+
+               output.printf("\n");
+               output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), dbus_name);
+               output.printf("%spublic errordomain %s {\n", get_indent(), errordomain_name);
+               update_indent(+1);
+
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case ERROR_ELTNAME:
+                               string dbus_error_name = iter->get_prop(NAME_ATTRNAME);
+                               string error_name = camel_case_to_upper_case(dbus_error_name);
+
+                               output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), dbus_error_name);
+                               output.printf("%s%s%s\n", get_indent(), error_name, iter->next == null ? "" : 
",");
+                               break;
+                       }
+               }
+
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+       }
+
+       private void generate_explicit_struct(string struct_name, Xml.Node* node)
+                       throws GeneratorError {
+               string dbus_name = node->get_prop(NAME_ATTRNAME);
+
+               INFO(@"Generating explicit struct $struct_name for $dbus_name");
+
+               output.printf("\n");
+               output.printf("%spublic struct %s {\n", get_indent(), struct_name);
+               update_indent(+1);
+
+               string ctor_signature = "%spublic %s (".printf(get_indent(), struct_name);
+               string ctor_body = "";
+
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case FIELD_ELTNAME:
+                               string field_name = transform_registered_name(iter->get_prop(NAME_ATTRNAME));
+                               string field_type = "unknown";
+                               try {
+                                       field_type = translate_type(iter->get_prop(TYPE_ATTRNAME),
+                                               iter->get_ns_prop(TYPE_ATTRNAME, FSO_NAMESPACE),
+                                               struct_name, get_namespace_name(dbus_name));
+                               } catch (GeneratorError.UNKNOWN_DBUS_TYPE ex) {
+                                       ERROR(@"In struct $struct_name field $field_name : Unknown dbus type 
$(ex.message)");
+                               }
+
+                               output.printf("%spublic %s %s;\n", get_indent(), field_type, field_name);
+                                       ctor_signature += "%s %s, ".printf(field_type, field_name);
+                                       ctor_body += "%sthis.%s = %s;\n".printf(get_indent(+1), field_name, 
field_name);
+                                       break;
+                               }
+                       }
+               string constructor = "%s ) {\n%s%s}".printf( ctor_signature.substring( 0, 
ctor_signature.length-2 ), ctor_body, get_indent() );
+
+               output.printf("\n%s\n", constructor);
+
+               INFO(@"Generating from_variant method for $struct_name");
+               output.printf("\n%spublic static %s from_variant (Variant v) {\n", get_indent(), struct_name);
+               update_indent(1);
+               output.printf("%sreturn v as %s;\n", get_indent(), struct_name);
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+               update_indent(-1);
+               output.printf("%s}", get_indent());
+       }
+
+       private void generate_struct(string name, string content_signature, string dbus_namespace)
+                                       throws GeneratorError {
+               INFO(@"Generating struct $name w/ signature $content_signature in dbus namespace 
$dbus_namespace");
+
+               output.printf("\n");
+               output.printf("%spublic struct %s {\n", get_indent(), name);
+               update_indent(+1);
+
+               int attribute_number = 1;
+               string signature = content_signature;
+               string tail = null;
+               while (signature != "") {
+                       string type = parse_type(signature, out tail, "", dbus_namespace);
+                       output.printf("%spublic %s attr%d;\n", get_indent(), type, attribute_number);
+                       attribute_number++;
+                       signature = tail;
+               }
+
+               update_indent(-1);
+               output.printf("%s}\n", get_indent());
+       }
+
+       private void generate_members(Xml.Node* node, string interface_name, string dbus_namespace, Synchrony 
synchrony)
+                                       throws GeneratorError {
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case METHOD_ELTNAME:
+                               generate_method(iter, interface_name, dbus_namespace, synchrony);
+                               break;
+                       case SIGNAL_ELTNAME:
+                               generate_signal(iter, interface_name, dbus_namespace);
+                               break;
+                       case PROPERTY_ELTNAME:
+                               generate_property(iter, interface_name, dbus_namespace);
+                               break;
+                       case ERROR_ELTNAME:
+                               generate_error(iter, interface_name);
+                               break;
+                       }
+               }
+       }
+
+       private void generate_method(Xml.Node* node, string interface_name, string dbus_namespace, Synchrony 
synchrony)
+                                       throws GeneratorError {
+
+               string realname = node->get_prop(NAME_ATTRNAME);
+               string name = transform_registered_name(uncapitalize(node->get_prop(NAME_ATTRNAME)));
+
+               INFO(@"   Generating method $name (originally $realname) for $interface_name");
+
+               int unknown_param_count = 0;
+
+               int out_param_count = get_out_parameter_count(node);
+
+               bool first_param = true;
+               bool first_error = true;
+               StringBuilder args_builder = new StringBuilder();
+               StringBuilder throws_builder = new StringBuilder();
+               string return_value_type = "void";
+               bool async_method = false;
+               bool noreply_method = false;
+               bool deprecated_method = false;
+               string deprecated_method_replaced_by = "";
+
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       switch (iter->name) {
+                       case ARG_ELTNAME:
+                               string? param_name = transform_registered_name(iter->get_prop(NAME_ATTRNAME));
+                               if(param_name == null || param_name == "") {
+                                       param_name = "param%i".printf(unknown_param_count);
+                                       unknown_param_count++;
+                               }
+                               string param_type = "unknown";
+                               try {
+                                       param_type = translate_type(iter->get_prop(TYPE_ATTRNAME),
+                                               iter->get_ns_prop(TYPE_ATTRNAME, FSO_NAMESPACE),
+                                               get_struct_name(interface_name, param_name),
+                                               dbus_namespace);
+                               } catch (GeneratorError.UNKNOWN_DBUS_TYPE ex) {
+                                       ERROR(@"In interface $interface_name method $name : Unknown dbus type 
$(ex.message)");
+                               }
+                               string? param_dir = iter->get_prop(DIRECTION_ATTRNAME);
+
+                               switch (param_dir) {
+                               case OUT_ATTRVALUE:
+                                       if (param_type == null) {
+                                               param_type = "void";
+                                       }
+                                       if (out_param_count != 1) {
+                                               if (!first_param) {
+                                                       args_builder.append(", ");
+                                               }
+
+                                               args_builder.append("out ");
+                                               args_builder.append(param_type);
+                                               args_builder.append(" ");
+                                               args_builder.append(param_name);
+                                               first_param = false;
+                                       } else {
+                                               return_value_type = param_type;
+                                       }
+                                       break;
+                               case IN_ATTRVALUE:
+                               default:
+                                       if (!first_param) {
+                                               args_builder.append(", ");
+                                       }
+
+                                       args_builder.append(param_type);
+                                       args_builder.append(" ");
+                                       args_builder.append(param_name);
+                                       first_param = false;
+                                       break;
+                               }
+                               break;
+                       case THROWS_ELTNAME:
+                               string errordomain_name = null;
+                               string fso_type = iter->get_prop(TYPE_ATTRNAME);
+                               if (fso_type != null) {
+                                       errordomain_name = error_name_index.get(fso_type);
+                               }
+                               if (errordomain_name == null) {
+                                       ERROR(@"In interface $interface_name method $name : Unknown dbus 
error $(fso_type)");
+                                       errordomain_name = "<unknown>";
+                               }
+
+                               if (!first_error) {
+                                       throws_builder.append(", ");
+                               }
+                               throws_builder.append(errordomain_name);
+                               first_error = false;
+                               break;
+                       case ANNOTATION_ELTNAME:
+                               string annotation_name = iter->get_prop(NAME_ATTRNAME);
+                               if (annotation_name == "org.freedesktop.DBus.GLib.Async") {
+                                       async_method = true;
+                               }
+                               if (annotation_name == "org.freedesktop.DBus.GLib.NoReply") {
+                                       noreply_method = true;
+                               }
+                               break;
+                       case DEPRECATED_ELTNAME:
+                               deprecated_method = true;
+                               deprecated_method_replaced_by = iter->get_prop(REPLACED_BY_ATTRNAME);
+                               break;
+                       }
+               }
+
+               if (async_method && noreply_method) {
+                       WARN(@"In interface $interface_name method $name : Requested both async and noreply; 
which is not supported by Vala. Will force sync.");
+                       async_method = false;
+               }
+
+               if (noreply_method && out_param_count > 0) {
+                       ERROR(@"In interface $interface_name method $name : noreply methods are not allowed 
to have out parameters!");
+               }
+
+               if (!first_error) {
+                       throws_builder.append(", ");
+               }
+               throws_builder.append("DBusError, IOError");
+
+               switch ( synchrony )
+               {
+                       case Synchrony.FORCE_SYNC:
+                               async_method = false;
+                               break;
+                       case Synchrony.FORCE_ASYNC:
+                               async_method = true;
+                               break;
+                       default:
+                               /* AUTO, leave it like it is */
+                               break;
+               }
+
+               output.printf("\n");
+               if (noreply_method) {
+                       output.printf("%s[DBus (name = \"%s\", no_reply = true)]\n", get_indent(), realname);
+               } else {
+                       output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), realname);
+               }
+               if (deprecated_method) {
+                       if (deprecated_method_replaced_by.length == 0)
+                               output.printf("[Version (deprecated = true)]\n");
+                       else output.printf("[Version (deprecated = true, replacement = 
\"%s\")]".printf(deprecated_method_replaced_by));
+               }
+               output.printf("%spublic abstract%s %s %s(%s) throws %s;\n",
+                       get_indent(), (async_method ? " async" : ""), return_value_type, name, 
args_builder.str, throws_builder.str);
+       }
+
+       private int get_out_parameter_count(Xml.Node* node) {
+               int out_param_count = 0;
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+                       if (iter->name != ARG_ELTNAME)
+                               continue;
+                       if (iter->get_prop(DIRECTION_ATTRNAME) != OUT_ATTRVALUE)
+                               continue;
+
+                       out_param_count++;
+               }
+               return out_param_count;
+       }
+
+       private void generate_signal(Xml.Node* node, string interface_name, string dbus_namespace)
+                                       throws GeneratorError {
+               string realname = node->get_prop(NAME_ATTRNAME);
+               string name = transform_registered_name(uncapitalize(node->get_prop(NAME_ATTRNAME)));
+
+               INFO(@"   Generating signal $name (originally $realname) for $interface_name");
+
+               int unknown_param_count = 0;
+
+               bool first_param = true;
+               StringBuilder args_builder = new StringBuilder();
+               for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
+                       if (iter->type != ElementType.ELEMENT_NODE)
+                               continue;
+
+                       if (iter->name != ARG_ELTNAME)
+                               continue;
+
+                       string param_name = transform_registered_name(iter->get_prop(NAME_ATTRNAME));
+                       if(param_name == null || param_name == "") {
+                               param_name = "param%i".printf(unknown_param_count);
+                               unknown_param_count++;
+                       }
+                       string param_type = "unknown";
+                       try {
+                               param_type = translate_type(iter->get_prop(TYPE_ATTRNAME),
+                                       iter->get_ns_prop(TYPE_ATTRNAME, FSO_NAMESPACE),
+                                       interface_name + capitalize(param_name),
+                                       dbus_namespace);
+                       } catch (GeneratorError.UNKNOWN_DBUS_TYPE ex) {
+                               ERROR(@"In interface $interface_name signal $name : Unknown dbus type 
$(ex.message)");
+                       }
+
+                       if (!first_param) {
+                               args_builder.append(", ");
+                       }
+
+                       args_builder.append(param_type);
+                       args_builder.append(" ");
+                       args_builder.append(param_name);
+                       first_param = false;
+               }
+
+               output.printf("\n");
+               output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), realname);
+               output.printf("%spublic signal void %s(%s);\n",
+                       get_indent(), name, args_builder.str);
+       }
+
+       private void generate_property(Xml.Node* node, string interface_name, string dbus_namespace)
+       {
+               string realname = node->get_prop(NAME_ATTRNAME);
+               string name = transform_registered_name(uncapitalize(node->get_prop(NAME_ATTRNAME)));
+
+               string typename = "unknown";
+               string rawtype = "";
+               try {
+                       rawtype = node->get_prop(TYPE_ATTRNAME);
+                       typename = translate_type(rawtype,
+                               node->get_ns_prop(TYPE_ATTRNAME, FSO_NAMESPACE),
+                               interface_name + capitalize(name),
+                               dbus_namespace);
+               } catch (GeneratorError ex) {
+                       if (ex is GeneratorError.UNKNOWN_DBUS_TYPE) {
+                               ERROR(@"In interface $interface_name property $name : Unknown dbus type 
$(ex.message)");
+                       } else {
+                               ERROR(@"In interface $interface_name property $name : Error $(ex.message)");
+                       }
+               }
+
+               string accesstype = "readwrite";
+               if (node->has_prop("access") != null) {
+                       accesstype = node->get_prop("access");
+                       if (accesstype != "readwrite" && accesstype != "readonly" && accesstype != "read") {
+                               ERROR(@"In interface $interface_name property $name : Unknown access type: 
$accesstype");
+                       }
+               }
+
+               INFO(@"   Generating property $name (originally $realname) of type $typename for 
$interface_name");
+
+               string owned_specifier = is_simple_type(rawtype) ? "" : "owned";
+               string accessimpl = (accesstype == "readonly" || accesstype == "read") ? @"$owned_specifier 
get;" : @"$owned_specifier get; set;";
+
+               output.printf("\n");
+               output.printf("%s[DBus (name = \"%s\")]\n", get_indent(), realname);
+               output.printf("%spublic abstract %s %s { %s }\n", get_indent(), typename, name, accessimpl);
+       }
+
+       private void generate_error(Xml.Node* node, string interface_name)
+                                       throws GeneratorError {
+       }
+
+       private void generate_proxy_getter(Xml.Node* node, owned string interface_name, Synchrony synchrony = 
Synchrony.AUTO)
+                                       throws GeneratorError {
+                       bool async_method = true;
+                       switch ( synchrony )
+                       {
+                               case Synchrony.FORCE_SYNC:
+                                       async_method = false;
+                                       break;
+                               case Synchrony.FORCE_ASYNC:
+                                       async_method = true;
+                                       break;
+                               default:
+                                       /* AUTO, leave it like it is */
+                                       break;
+                       }
+                       if ( !async_method ) {
+                               interface_name = interface_name + "Sync";
+                       }
+       }
+
+       private string translate_type(string type, string? fso_type, string type_name, string dbus_namespace)
+                                       throws GeneratorError {
+               string tail = null;
+               if (fso_type != null) {
+                       var vala_type = name_index.get(fso_type);
+                       if (vala_type == null) {
+                               throw new GeneratorError.UNKNOWN_DBUS_TYPE(fso_type);
+                       }
+                       return vala_type + (type.has_prefix("a") ? "[]" : "");
+               }
+               return parse_type(type, out tail, type_name, dbus_namespace).replace("][", ",");
+       }
+
+       private bool is_simple_type(string type)
+       {
+               switch (type) {
+                       case "b":
+                       case "i":
+                       case "n":
+                       case "q":
+                       case "t":
+                       case "u":
+                       case "x":
+                       case "d":
+                               return true;
+               }
+               return false;
+       }
+
+       private string parse_type(string type, out string tail, string type_name, string dbus_namespace)
+                                       throws GeneratorError {
+               tail = type.substring(1);
+               if (type.has_prefix("y")) {
+                       return "uint8"; // uchar only works since post-vala 0.8.0 (see 
c4cf64b6590e5cce21febf98b1f3ff935d921fd5)
+               } else if (type.has_prefix("b")) {
+                       return "bool";
+               } else if (type.has_prefix("n") || type.has_prefix("i")) {
+                       return "int";
+               } else if (type.has_prefix("q") || type.has_prefix("u")) {
+                       return "uint";
+               } else if (type.has_prefix("x")) {
+                       return "int64";
+               } else if (type.has_prefix("t")) {
+                       return "uint64";
+               } else if (type.has_prefix("d")) {
+                       return "double";
+               } else if (type.has_prefix("s")) {
+                       return "string";
+               } else if (type.has_prefix("o")) {
+                       return "GLib.ObjectPath"; // needs to be prefixed post vala 0.9.2 (see 
142ca8fe0e5b4b8058d4913e909ccc820b6f7768 and 9a650b7f3bb796c36e31a7c649c7f59e8292631e)
+               } else if (type.has_prefix("v")) {
+                       return "GLib.Variant";
+               } else if (type.has_prefix("a{") && type.has_suffix("}")) {
+                       string tmp_type = get_subsignature(type, '{', '}', out tail);
+                       string tail2 = null;
+                       string tail3 = null;
+
+                       StringBuilder vala_type = new StringBuilder();
+                       vala_type.append("GLib.HashTable<");
+                       string foo = parse_type(tmp_type, out tail2, plural_to_singular(type_name) + "Key", 
dbus_namespace);
+                       vala_type.append(foo);
+                       vala_type.append(", ");
+
+                       string value_type = parse_type(tail2, out tail3, plural_to_singular(type_name), 
dbus_namespace);
+                       if (value_type == "GLib.Value") {
+                               value_type += "?";
+                       }
+                       vala_type.append(value_type);
+                       vala_type.append(">");
+
+                       return vala_type.str;
+               } else if (type.has_prefix("a")) {
+                       string tail2 = null;
+                       return parse_type(tail, out tail2, plural_to_singular(type_name), dbus_namespace) + 
"[]";
+               } else if (type.has_prefix("(") && type.has_suffix(")")) {
+                       string sub_type = get_subsignature(type, '(', ')', out tail);
+                       int number = 2;
+                       string unique_type_name = type_name +"Struct";
+                       while (structs_to_generate.has_key(unique_type_name)) {
+                               unique_type_name = "%s%d".printf(unique_type_name, number++);
+                       }
+
+                       if (!name_index.has_key(dbus_namespace + "." + unique_type_name)) {
+                               structs_to_generate.set(unique_type_name, sub_type);
+                       }
+                       return unique_type_name;
+               }
+               throw new GeneratorError.UNKNOWN_DBUS_TYPE(@"dbustype: '$type' unknown");
+       }
+
+       private string get_struct_name(string interface_name, string param_name) {
+               string striped_interface_name = strip_namespace(interface_name);
+               string name = capitalize(param_name);
+               return name.has_prefix(striped_interface_name) ? name : striped_interface_name + name;
+       }
+
+       private string get_namespace_name(string interface_name) {
+               long last_dot = interface_name.length - 1;
+               while (last_dot >= 0 && interface_name[last_dot] != '.') {
+                       last_dot--;
+               }
+               return interface_name.substring(0, last_dot);
+       }
+
+       private string strip_namespace(string interface_name) {
+               long last_dot = interface_name.length - 1;
+               while (last_dot >= 0 && interface_name[last_dot] != '.') {
+                       last_dot--;
+               }
+               return interface_name.substring(last_dot + 1, interface_name.length - last_dot - 1);
+       }
+
+       private string capitalize(string type_name) {
+               string[] parts = type_name.split("_");
+               StringBuilder capitalized_name = new StringBuilder();
+               foreach (string part in parts) {
+                       if (part != "") {
+                               capitalized_name.append(part.substring(0, 1).up());
+                               capitalized_name.append(part.substring(1, part.length - 1));
+                       }
+               }
+               return capitalized_name.str;
+       }
+
+       private string uncapitalize(string name) {
+               StringBuilder uncapitalized_name = new StringBuilder();
+               for (int i = 0; i < name.length; i++) {
+                       unichar c = name[i];
+                       if (c.isupper()) {
+                               if (i > 0)
+                                       uncapitalized_name.append_unichar('_');
+                               uncapitalized_name.append_unichar(c.tolower());
+                       } else {
+                               uncapitalized_name.append_unichar(c);
+                       }
+               }
+               return transform_registered_name(uncapitalized_name.str);
+       }
+
+       private string normalized_to_upper_case(string name) {
+               return name.replace("-", "_").up();
+       }
+
+       private string camel_case_to_upper_case(string name) {
+               return uncapitalize(name).up();
+       }
+
+       private string transform_registered_name(string? name) {
+               if (name != null && registered_names.contains(name)) {
+                       return name + "_";
+               }
+               return name;
+       }
+
+       private string plural_to_singular(string type_name) {
+               if (type_name.has_suffix("ies"))
+                       return type_name.substring(0, type_name.length - 3) + "y";
+               else if (type_name.has_suffix("ses"))
+                       return type_name.substring(0, type_name.length - 2);
+               else if (type_name.has_suffix("us"))
+                       return type_name;
+               else if (type_name.has_suffix("i"))
+                       return type_name.substring(0, type_name.length - 1) + "o";
+               else if (type_name.has_suffix("s"))
+                       return type_name.substring(0, type_name.length - 1);
+               else return type_name;
+       }
+
+       private int indentSize = 0;
+
+       private string get_indent(int offset = 0) {
+               return string.nfill(indentSize + offset, '\t');
+       }
+
+       private void update_indent(int increment) {
+               indentSize += increment;
+       }
+
+       private string get_subsignature( string s, char start, char end, out string tail ) {
+               unowned char[] data = (char[])s;
+               int iter = 0;
+               int counter = 0;
+               int begin = 0;
+               char c;
+
+               for(iter = 0; iter < s.length; iter++) {
+                       c = data[iter];
+                       if(c == start) {
+                               if( counter == 0 ) {
+                                       begin = iter;
+                               }
+                               counter ++;
+                       }
+                       else if(c == end) {
+                               counter --;
+                               if(counter == 0) {
+                                       break;
+                               }
+                       }
+               }
+               tail = s.substring( iter + 1, -1 );
+               var tmp = s.substring( begin + 1, iter - begin - 1);
+               return tmp;
+    }
+}
diff --git a/dbusgen/valadbusgen.vala b/dbusgen/valadbusgen.vala
new file mode 100644
index 0000000..4ba5de3
--- /dev/null
+++ b/dbusgen/valadbusgen.vala
@@ -0,0 +1,176 @@
+/* valadbusigen.vala
+ *
+ * Copyright (C) 2017 Chris Daley
+ * Copyright (C) 2006-2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Chris Daley <chebizarro gmail com>
+ *     Jürg Billeter <j bitron ch>
+ */
+
+using GLib;
+
+class Vala.DBUSGen {
+       static string directory;
+       static bool version;
+       static bool quiet_mode;
+       static bool disable_warnings;
+       [CCode (array_length = false, array_null_terminated = true)]
+       static string[] sources;
+       [CCode (array_length = false, array_null_terminated = true)]
+       static string[] api_path;
+       [CCode (array_length = false, array_null_terminated = true)]
+       static string[] gir_directories;
+       [CCode (array_length = false, array_null_terminated = true)]
+       static string[] metadata_directories;
+       static string library;
+       [CCode (array_length = false, array_null_terminated = true)]
+       static string[] packages;
+       static bool nostdpkg;
+
+       CodeContext context;
+
+       const OptionEntry[] options = {
+               { "vapidir", 0, 0, OptionArg.FILENAME_ARRAY, ref api_path, "Look for package bindings in 
DIRECTORY", "DIRECTORY..." },
+               { "girdir", 0, 0, OptionArg.FILENAME_ARRAY, ref gir_directories, "Look for GIR bindings in 
DIRECTORY", "DIRECTORY..." },
+               { "metadatadir", 0, 0, OptionArg.FILENAME_ARRAY, ref metadata_directories, "Look for GIR 
.metadata files in DIRECTORY", "DIRECTORY..." },
+               { "nostdpkg", 0, 0, OptionArg.NONE, ref nostdpkg, "Do not include standard packages", null },
+               { "pkg", 0, 0, OptionArg.STRING_ARRAY, ref packages, "Include binding for PACKAGE", 
"PACKAGE..." },
+               { "library", 0, 0, OptionArg.STRING, ref library, "Library name", "NAME" },
+               { "directory", 'd', 0, OptionArg.FILENAME, ref directory, "Output directory", "DIRECTORY" },
+               { "disable-warnings", 0, 0, OptionArg.NONE, ref disable_warnings, "Disable warnings", null },
+               { "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null },
+               { "quiet", 'q', 0, OptionArg.NONE, ref quiet_mode, "Do not print messages to the console", 
null },
+               { "", 0, 0, OptionArg.FILENAME_ARRAY, ref sources, null, "FILE..." },
+               { null }
+       };
+       
+       private int quit () {
+               if (context.report.get_errors () == 0) {
+                       if (!quiet_mode) {
+                               stdout.printf ("Generation succeeded - %d warning(s)\n", 
context.report.get_warnings ());
+                       }
+                       return 0;
+               } else {
+                       if (!quiet_mode) {
+                               stdout.printf ("Generation failed: %d error(s), %d warning(s)\n", 
context.report.get_errors (), context.report.get_warnings ());
+                       }
+                       return 1;
+               }
+       }
+       
+       private int run () {
+               context = new CodeContext ();
+               context.profile = Profile.GOBJECT;
+               context.vapi_directories = vapi_directories;
+               context.gir_directories = gir_directories;
+               context.metadata_directories = metadata_directories;
+               context.report.enable_warnings = !disable_warnings;
+               context.report.set_verbose_errors (!quiet_mode);
+               CodeContext.push (context);
+               context.nostdpkg = nostdpkg;
+
+               if (!nostdpkg) {
+                       /* default package */
+                       context.add_external_package ("glib-2.0");
+                       context.add_external_package ("gobject-2.0");
+               }
+
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+
+
+               if (packages != null) {
+                       foreach (string package in packages) {
+                               context.add_external_package (package);
+                       }
+                       packages = null;
+               }
+               
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+
+               foreach (string source in sources) {
+                       if (FileUtils.test (source, FileTest.EXISTS)) {
+                               var source_file = new SourceFile (context, SourceFileType.PACKAGE, source);
+                               source_file.explicit = true;
+                               context.add_source_file (source_file);
+                       } else {
+                               Report.error (null, "%s not found".printf (source));
+                       }
+               }
+               
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+               
+               var parser = new DBusParser ();
+               parser.parse (context);
+               
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+                               
+               context.check ();
+
+               if (context.report.get_errors () > 0) {
+                       return quit ();
+               }
+
+               var interface_writer = new CodeWriter ();
+               
+               var vapi_filename = "%s.vala".printf (library);
+               if (directory != null) {
+                       vapi_filename = Path.build_path ("/", directory, vapi_filename);
+               }
+
+               interface_writer.write_file (context, vapi_filename);
+                       
+               library = null;
+               
+               return quit ();
+       }
+       
+       static int main (string[] args) {
+               Intl.setlocale (LocaleCategory.ALL, "");
+               try {
+                       var opt_context = new OptionContext ("- Vala DBus Interface Generator");
+                       opt_context.set_help_enabled (true);
+                       opt_context.add_main_entries (options, null);
+                       opt_context.parse (ref args);
+               } catch (OptionError e) {
+                       stdout.printf ("%s\n", e.message);
+                       stdout.printf ("Run '%s --help' to see a full list of available command line 
options.\n", args[0]);
+                       return 1;
+               }
+
+               if (version) {
+                       stdout.printf ("Vala DBus Interface Generator %s\n", Config.BUILD_VERSION);
+                       return 0;
+               }
+
+               if (sources == null) {
+                       stderr.printf ("No API file specified.\n");
+                       return 1;
+               }
+               
+               var vapigen = new DBUSGen ();
+               return vapigen.run ();
+       }
+}
diff --git a/dbusgen/valadbusparser.vala b/dbusgen/valadbusparser.vala
new file mode 100644
index 0000000..d392f6f
--- /dev/null
+++ b/dbusgen/valadbusparser.vala
@@ -0,0 +1,3188 @@
+/* valadbusparser.vala
+ *
+ * Copyright (C) 2017 Chris Daley
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Chris Daley <chebizarro gmail com>
+ */
+
+using GLib;
+using Xml;
+
+/**
+ * Code visitor parsing all DBus interface files.
+ */
+public class Vala.DBusParser : CodeVisitor {
+
+       private CodeContext context;
+
+       private SourceFile current_source_file;
+
+       private SourceReference current_source_reference;
+       
+       private Namespace current_namespace;
+
+
+
+       /**
+        * Parse all source files in the specified code context and build a
+        * code tree.
+        *
+        * @param context a code context
+        */
+       public void parse (CodeContext context) {
+
+               Parser.init();
+
+               this.context = context;
+               context.accept (this);
+               
+               Parser.cleanup();
+
+       }
+
+       public override void visit_namespace (Namespace ns) {
+               ns.accept_children (this);
+       }
+
+       public override void visit_class (Class cl) {
+               visit_type (cl);
+       }
+
+       public override void visit_struct (Struct st) {
+               visit_type (st);
+       }
+
+       public override void visit_interface (Interface iface) {
+               visit_type (iface);
+       }
+
+       public override void visit_enum (Enum en) {
+               visit_type (en);
+       }
+
+       public override void visit_error_domain (ErrorDomain ed) {
+               visit_type (ed);
+       }
+
+       public override void visit_delegate (Delegate d) {
+               visit_type (d);
+       }
+
+       private void visit_type (TypeSymbol t) {
+               if (!cname_type_map.contains (get_cname (t))) {
+                       cname_type_map[get_cname (t)] = t;
+               }
+       }
+
+       public override void visit_source_file (SourceFile source_file) {
+               if (source_file.filename.has_suffix (".xml")) {
+                       parse_file (source_file);
+               }
+       }
+       
+       private void parse_file (SourceFile source_file) {
+               string metadata_filename = "%s.metadata".printf (source_file.filename.substring (0, 
source_file.filename.length - ".gi".length));
+
+               current_source_file = source_file;
+
+               codenode_attributes_map = new HashMap<string,string> (str_hash, str_equal);
+               codenode_attributes_patterns = new HashMap<PatternSpec*,string> (direct_hash, 
(EqualFunc<PatternSpec>) PatternSpec.equal);
+
+               if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
+                       try {
+                               string metadata;
+                               FileUtils.get_contents (metadata_filename, out metadata, null);
+                               
+                               foreach (unowned string line in metadata.split ("\n")) {
+                                       if (line.has_prefix ("#")) {
+                                               // ignore comment lines
+                                               continue;
+                                       }
+
+                                       var tokens = line.split (" ", 2);
+
+                                       if (null == tokens[0]) {
+                                               continue;
+                                       }
+
+                                       if (-1 != tokens[0].index_of_char ('*')) {
+                                               PatternSpec* pattern = new PatternSpec (tokens[0]);
+                                               codenode_attributes_patterns[pattern] = tokens[0];
+                                       }
+                                       
+                                       codenode_attributes_map[tokens[0]] = tokens[1];
+                               }
+                       } catch (FileError e) {
+                               Report.error (null, "Unable to read metadata file: %s".printf (e.message));
+                       }
+               }
+       
+               try {
+                       var modules = Idl.parse_file (source_file.filename);
+                       
+                       current_source_reference = new SourceReference (source_file, SourceLocation (null, 0, 
0), SourceLocation (null, 0, 0));
+                       
+                       foreach (weak IdlModule module in modules) {
+                               var ns = parse_module (module);
+                               if (ns != null) {
+                                       context.root.add_namespace (ns);
+                               }
+                       }
+               } catch (MarkupError e) {
+                       Report.error (null, "Unable to parse GIDL file: %s".printf (e.message));
+               }
+       }
+
+       private string fix_type_name (string type_name, Symbol container) {
+               var attributes = get_attributes (type_name);
+               if (attributes != null) {
+                       foreach (string attr in attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "name") {
+                                       return eval (nv[1]);
+                               }
+                       }
+               }
+
+               if (type_name.has_prefix (container.name)) {
+                       return type_name.substring (container.name.length);
+               } else {
+                       var cprefix = get_cprefix (container);
+                       if (type_name.has_prefix (cprefix)) {
+                               return type_name.substring (cprefix.length);;
+                       }
+               }
+
+               return type_name;
+       }
+
+       private string fix_const_name (string const_name, Symbol container) {
+               var pref = get_lower_case_cprefix (container).ascii_up ();
+               if (const_name.has_prefix (pref)) {
+                       return const_name.substring (pref.length);
+               }
+               return const_name;
+       }
+
+       private string get_cheader_filename (Symbol sym) {
+               var cheader_filename = sym.get_attribute_string ("CCode", "cheader_filename");
+               if (cheader_filename != null) {
+                       return cheader_filename;
+               }
+               if (sym.parent_symbol != null) {
+                       return get_cheader_filename (sym.parent_symbol);
+               } else if (sym.source_reference != null) {
+                       return sym.source_reference.file.get_cinclude_filename ();
+               }
+               return "";
+       }
+
+       private string get_cname (Symbol sym, Symbol? container = null) {
+               if (container == null) {
+                       container = sym.parent_symbol;
+               }
+               var cname = sym.get_attribute_string ("CCode", "cname");
+               if (cname != null) {
+                       return cname;
+               }
+               if (sym is Method) {
+                       var name = sym.name;
+                       if (sym is CreationMethod) {
+                               if (name == null || name == ".new") {
+                                       name = "new";
+                               } else {
+                                       name = "new_%s".printf (name);
+                               }
+                       }
+                       if (container != null) {
+                               return "%s%s".printf (get_lower_case_cprefix (container), name);
+                       } else {
+                               return name;
+                       }
+               } else {
+                       if (container != null) {
+                               return "%s%s".printf (get_cprefix (container), sym.name);
+                       } else {
+                               return sym.name;
+                       }
+               }
+       }
+
+       private string get_finish_cname (Method m) {
+               var finish_cname = m.get_attribute_string ("CCode", "finish_name");
+               if (finish_cname != null) {
+                       return finish_cname;
+               }
+               var result = get_cname (m);
+               if (result.has_suffix ("_async")) {
+                       result = result.substring (0, result.length - "_async".length);
+               }
+               return result + "_finish";
+       }
+
+       private string get_lower_case_cname (Symbol sym) {
+               var lower_case_csuffix = Symbol.camel_case_to_lower_case (sym.name);
+               if (sym is ObjectTypeSymbol) {
+                       // remove underscores in some cases to avoid conflicts of type macros
+                       if (lower_case_csuffix.has_prefix ("type_")) {
+                               lower_case_csuffix = "type" + lower_case_csuffix.substring ("type_".length);
+                       } else if (lower_case_csuffix.has_prefix ("is_")) {
+                               lower_case_csuffix = "is" + lower_case_csuffix.substring ("is_".length);
+                       }
+                       if (lower_case_csuffix.has_suffix ("_class")) {
+                               lower_case_csuffix = lower_case_csuffix.substring (0, 
lower_case_csuffix.length - "_class".length) + "class";
+                       }
+               }
+               if (sym.parent_symbol != null) {
+                       return "%s%s".printf (get_lower_case_cprefix (sym.parent_symbol), lower_case_csuffix);
+               } else {
+                       return lower_case_csuffix;
+               }
+       }
+
+       private string get_lower_case_cprefix (Symbol sym) {
+               if (sym.name == null) {
+                       return "";
+               }
+               string cprefix;
+               cprefix = sym.get_attribute_string ("CCode", "lower_case_cprefix");
+               if (cprefix == null && (sym is ObjectTypeSymbol || sym is Struct)) {
+                       cprefix = sym.get_attribute_string ("CCode", "cprefix");
+               }
+               if (cprefix != null) {
+                       return cprefix;
+               }
+               return get_lower_case_cname (sym) + "_";
+       }
+
+       public string get_cprefix (Symbol sym) {
+               if (sym is ObjectTypeSymbol) {
+                       return get_cname (sym);
+               } else if (sym is Enum || sym is ErrorDomain) {
+                       return "%s_".printf (get_lower_case_cname (sym).ascii_up ());
+               } else if (sym is Namespace) {
+                       if (sym.name != null) {
+                               var cprefix = sym.get_attribute_string ("CCode", "cprefix");
+                               if (cprefix != null) {
+                                       return cprefix;
+                               }
+                               if (sym.parent_symbol != null) {
+                                       return "%s%s".printf (get_cprefix (sym.parent_symbol), sym.name);
+                               } else {
+                                       return sym.name;
+                               }
+                       } else {
+                               return "";
+                       }
+               } else if (sym.name != null) {
+                       return sym.name;
+               }
+               return "";
+       }
+
+       private string[] get_attributes_for_node (IdlNode node) {
+               string name;
+
+               if (node.type == IdlNodeTypeId.FUNCTION) {
+                       name = ((IdlNodeFunction) node).symbol;
+               } else if (node.type == IdlNodeTypeId.SIGNAL) {
+                       name = "%s::%s".printf (get_cname (current_data_type), node.name);
+               } else if (node.type == IdlNodeTypeId.PROPERTY) {
+                       name = "%s:%s".printf (get_cname (current_data_type), node.name);
+               } else if (node.type == IdlNodeTypeId.FIELD) {
+                       name = "%s.%s".printf (get_cname (current_data_type), node.name);
+               } else {
+                       name = node.name;
+               }
+
+               return get_attributes (name);
+       }
+
+       private void add_symbol_to_container (Symbol container, Symbol sym) {
+               if (container is Class) {
+                       unowned Class cl = (Class) container;
+
+                       if (sym is Class) {
+                               cl.add_class ((Class) sym);
+                       } else if (sym is Constant) {
+                               cl.add_constant ((Constant) sym);
+                       } else if (sym is Enum) {
+                               cl.add_enum ((Enum) sym);
+                       } else if (sym is Field) {
+                               cl.add_field ((Field) sym);
+                       } else if (sym is Method) {
+                               cl.add_method ((Method) sym);
+                       } else if (sym is Property) {
+                               cl.add_property ((Property) sym);
+                       } else if (sym is Signal) {
+                               cl.add_signal ((Signal) sym);
+                       } else if (sym is Struct) {
+                               cl.add_struct ((Struct) sym);
+                       }
+               } else if (container is Enum) {
+                       unowned Enum en = (Enum) container;
+
+                       if (sym is EnumValue) {
+                               en.add_value ((EnumValue) sym);
+                       } else if (sym is Constant) {
+                               en.add_constant ((Constant) sym);
+                       } else if (sym is Method) {
+                               en.add_method ((Method) sym);
+                       }
+               } else if (container is Interface) {
+                       unowned Interface iface = (Interface) container;
+
+                       if (sym is Class) {
+                               iface.add_class ((Class) sym);
+                       } else if (sym is Constant) {
+                               iface.add_constant ((Constant) sym);
+                       } else if (sym is Enum) {
+                               iface.add_enum ((Enum) sym);
+                       } else if (sym is Field) {
+                               iface.add_field ((Field) sym);
+                       } else if (sym is Method) {
+                               iface.add_method ((Method) sym);
+                       } else if (sym is Property) {
+                               iface.add_property ((Property) sym);
+                       } else if (sym is Signal) {
+                               iface.add_signal ((Signal) sym);
+                       } else if (sym is Struct) {
+                               iface.add_struct ((Struct) sym);
+                       }
+               } else if (container is Namespace) {
+                       unowned Namespace ns = (Namespace) container;
+
+                       if (sym is Namespace) {
+                               ns.add_namespace ((Namespace) sym);
+                       } else if (sym is Class) {
+                               ns.add_class ((Class) sym);
+                       } else if (sym is Constant) {
+                               ns.add_constant ((Constant) sym);
+                       } else if (sym is Delegate) {
+                               ns.add_delegate ((Delegate) sym);
+                       } else if (sym is Enum) {
+                               ns.add_enum ((Enum) sym);
+                       } else if (sym is ErrorDomain) {
+                               ns.add_error_domain ((ErrorDomain) sym);
+                       } else if (sym is Field) {
+                               ns.add_field ((Field) sym);
+                       } else if (sym is Interface) {
+                               ns.add_interface ((Interface) sym);
+                       } else if (sym is Method) {
+                               ns.add_method ((Method) sym);
+                       } else if (sym is Namespace) {
+                               ns.add_namespace ((Namespace) sym);
+                       } else if (sym is Struct) {
+                               ns.add_struct ((Struct) sym);
+                       }
+               } else if (container is Struct) {
+                       unowned Struct st = (Struct) container;
+
+                       if (sym is Constant) {
+                               st.add_constant ((Constant) sym);
+                       } else if (sym is Field) {
+                               st.add_field ((Field) sym);
+                       } else if (sym is Method) {
+                               st.add_method ((Method) sym);
+                       } else if (sym is Property) {
+                               st.add_property ((Property) sym);
+                       }
+               }
+
+               if (!(sym is Namespace) && container is Namespace) {
+                       // set C headers
+                       sym.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename (sym));
+               }
+       }
+
+       private void parse_node (IdlNode node, IdlModule module, Symbol container) {
+               if (node.type == IdlNodeTypeId.CALLBACK) {
+                       var cb = parse_delegate ((IdlNodeFunction) node);
+                       if (cb == null) {
+                               return;
+                       }
+                       cb.name = fix_type_name (cb.name, container);
+                       add_symbol_to_container (container, cb);
+                       current_source_file.add_node (cb);
+               } else if (node.type == IdlNodeTypeId.STRUCT) {
+                       parse_struct ((IdlNodeStruct) node, container, module);
+               } else if (node.type == IdlNodeTypeId.UNION) {
+                       parse_union ((IdlNodeUnion) node, container, module);
+               } else if (node.type == IdlNodeTypeId.BOXED) {
+                       parse_boxed ((IdlNodeBoxed) node, container, module);
+               } else if (node.type == IdlNodeTypeId.ENUM) {
+                       parse_enum ((IdlNodeEnum) node, container, module, false);
+               } else if (node.type == IdlNodeTypeId.FLAGS) {
+                       parse_enum ((IdlNodeEnum) node, container, module, true);
+               } else if (node.type == IdlNodeTypeId.OBJECT) {
+                       parse_object ((IdlNodeInterface) node, container, module);
+               } else if (node.type == IdlNodeTypeId.INTERFACE) {
+                       parse_interface ((IdlNodeInterface) node, container, module);
+               } else if (node.type == IdlNodeTypeId.CONSTANT) {
+                       var c = parse_constant ((IdlNodeConstant) node);
+                       if (c != null) {
+                               c.name = fix_const_name (c.name, container);
+                               add_symbol_to_container (container, c);
+                               current_source_file.add_node (c);
+                       }
+               } else if (node.type == IdlNodeTypeId.FUNCTION) {
+                       var m = parse_function ((IdlNodeFunction) node);
+                       if (m != null) {
+                               m.binding = MemberBinding.STATIC;
+                               add_symbol_to_container (container, m);
+                               current_source_file.add_node (m);
+                       }
+               }
+       }
+
+       private Symbol? get_container_from_name (string name) {
+               var path = name.split (".");
+               Symbol? cp = current_namespace;
+               if (cp.parent_symbol != context.root) {
+                       cp = cp.parent_symbol;
+               }
+               Symbol? cc = null;
+
+               foreach ( unowned string tok in path ) {
+                       cc = cp.scope.lookup (tok) as Symbol;
+                       if ( cc == null ) {
+                               cc = new Namespace (tok, current_source_reference);
+                               add_symbol_to_container (cp, cc);
+                       }
+                       cp = cc;
+               }
+
+               return cc;
+       }
+
+       private Namespace? parse_module (IdlModule module) {
+               Symbol sym = context.root.scope.lookup (module.name);
+               Namespace ns;
+               if (sym is Namespace) {
+                       ns = (Namespace) sym;
+                       if (ns.external_package) {
+                               ns.attributes = null;
+                               ns.source_reference = current_source_reference;
+                       }
+               } else {
+                       ns = new Namespace (module.name, current_source_reference);
+               }
+
+               current_namespace = ns;
+
+               var attributes = get_attributes (ns.name);
+               if (attributes != null) {
+                       foreach (string attr in attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "cheader_filename") {
+                                       ns.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
+                               } else if (nv[0] == "cprefix") {
+                                       ns.set_attribute_string ("CCode", "cprefix", eval (nv[1]));
+                               } else if (nv[0] == "lower_case_cprefix") {
+                                       ns.set_attribute_string ("CCode", "lower_case_cprefix",  eval 
(nv[1]));
+                               } else if (nv[0] == "gir_namespace") {
+                                       ns.source_reference.file.gir_namespace = eval (nv[1]);
+                                       ns.set_attribute_string ("CCode", "gir_namespace", eval (nv[1]));
+                               } else if (nv[0] == "gir_version") {
+                                       ns.source_reference.file.gir_version = eval (nv[1]);
+                                       ns.set_attribute_string ("CCode", "gir_version", eval (nv[1]));
+                               } else if (nv[0] == "deprecated") {
+                                       if (eval (nv[1]) == "1") {
+                                               ns.set_attribute_bool ("Version", "deprecated", true);
+                                       }
+                               } else if (nv[0] == "replacement") {
+                                       ns.set_attribute_string ("Version", "replacement", eval (nv[1]));
+                               } else if (nv[0] == "deprecated_since") {
+                                       ns.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
+                               }
+                       }
+               }
+
+               var deferred = new ArrayList<unowned IdlNode> ();
+
+               foreach (weak IdlNode node in module.entries) {
+                       bool is_deferred = false;
+                       var child_attributes = get_attributes_for_node (node);
+                       if (child_attributes != null) {
+                               foreach (unowned string attr in child_attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "parent") {
+                                               deferred.add (node);
+                                               is_deferred = true;
+                                       }
+                               }
+                       }
+
+                       if (!is_deferred) {
+                               parse_node (node, module, ns);
+                       }
+               }
+
+               foreach (unowned IdlNode node in deferred) {
+                       Symbol container = ns;
+                       var child_attributes = get_attributes_for_node (node);
+                       if (child_attributes != null) {
+                               foreach (unowned string attr in child_attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "parent") {
+                                               container = get_container_from_name (eval (nv[1]));
+                                       }
+                               }
+                       }
+
+                       if (container is Namespace) {
+                               current_namespace = (Namespace) container;
+                       } else {
+                               current_data_type = (TypeSymbol) container;
+                       }
+                       parse_node (node, module, container);
+                       current_namespace = ns;
+                       current_data_type = null;
+               }
+
+               current_namespace = null;
+
+               if (sym is Namespace) {
+                       return null;
+               }
+               return ns;
+       }
+       
+       private Delegate? parse_delegate (IdlNodeFunction f_node) {
+               weak IdlNode node = (IdlNode) f_node;
+
+               var return_type = parse_param (f_node.result);
+
+               var cb = new Delegate (node.name, return_type, current_source_reference);
+               cb.access = SymbolAccessibility.PUBLIC;
+               cb.has_target = false;
+
+               bool check_has_target = true;
+               bool suppress_throws = false;
+               string? error_types = null;
+
+               var attributes = get_attributes (node.name);
+               if (attributes != null) {
+                       foreach (string attr in attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "hidden") {
+                                       if (eval (nv[1]) == "1") {
+                                               return null;
+                                       }
+                               } else if (nv[0] == "cheader_filename") {
+                                       cb.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
+                               } else if (nv[0] == "has_target") {
+                                       if (eval (nv[1]) == "0") {
+                                               check_has_target = false;
+                                       } else if (eval (nv[1]) == "1") {
+                                               cb.has_target = true;
+                                       }
+                               } else if (nv[0] == "transfer_ownership") {
+                                       if (eval (nv[1]) == "1") {
+                                               return_type.value_owned = true;
+                                       }
+                               } else if (nv[0] == "is_array") {
+                                       if (eval (nv[1]) == "1") {
+                                               return_type.value_owned = true;
+                                               return_type = new ArrayType (return_type, 1, 
return_type.source_reference);
+                                               cb.return_type = return_type;
+                                       }
+                               } else if (nv[0] == "throws") {
+                                       if (eval (nv[1]) == "0") {
+                                               suppress_throws = true;
+                                       }
+                               } else if (nv[0] == "error_types") {
+                                       error_types = eval (nv[1]);
+                               } else if (nv[0] == "array_length_type") {
+                                       cb.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
+                               } else if (nv[0] == "type_name") {
+                                       cb.return_type = return_type = parse_type_from_string (eval (nv[1]), 
return_type.value_owned);
+                               } else if (nv[0] == "deprecated") {
+                                       if (eval (nv[1]) == "1") {
+                                               cb.set_attribute_bool ("Version", "deprecated", true);
+                                       }
+                               } else if (nv[0] == "replacement") {
+                                       cb.set_attribute_string ("Version", "replacement", eval (nv[1]));
+                               } else if (nv[0] == "deprecated_since") {
+                                       cb.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
+                               } else if (nv[0] == "type_arguments") {
+                                       parse_type_arguments_from_string (return_type, eval (nv[1]));
+                               } else if (nv[0] == "instance_pos") {
+                                       cb.set_attribute_double ("CCode", "instance_pos", double.parse (eval 
(nv[1])));
+                               } else if (nv[0] == "type_parameters") {
+                                       foreach (string type_param_name in eval (nv[1]).split (",")) {
+                                               cb.add_type_parameter (new TypeParameter (type_param_name, 
current_source_reference));
+                                       }
+                               } else if (nv[0] == "experimental") {
+                                       if (eval (nv[1]) == "1") {
+                                               cb.set_attribute_bool ("Version", "experimental", true);
+                                       }
+                               }
+                       }
+               }
+
+               uint remaining_params = f_node.parameters.length ();
+               foreach (weak IdlNodeParam param in f_node.parameters) {
+                       weak IdlNode param_node = (IdlNode) param;
+
+                       if (check_has_target && remaining_params == 1 && (param_node.name == "user_data" || 
param_node.name == "data")) {
+                               // hide user_data parameter for instance delegates
+                               cb.has_target = true;
+                       } else {
+                               // check for GError parameter
+                               if (suppress_throws == false && param_is_exception (param)) {
+                                       if (error_types == null)
+                                               cb.add_error_type (parse_type (param.type));
+                                       remaining_params--;
+                                       continue;
+                               }
+
+                               string param_name = param_node.name;
+                               if (param_name == "string") {
+                                       // avoid conflict with string type
+                                       param_name = "str";
+                               } else if (param_name == "self") {
+                                       // avoid conflict with delegate target
+                                       param_name = "_self";
+                               }
+
+                               ParameterDirection direction;
+                               var param_type = parse_param (param, out direction);
+                               var p = new Parameter (param_name, param_type);
+                               p.direction = direction;
+
+                               bool hide_param = false;
+                               bool show_param = false;
+                               bool array_requested = false;
+                               bool out_requested = false;
+                               attributes = get_attributes ("%s.%s".printf (node.name, param_node.name));
+                               if (attributes != null) {
+                                       foreach (string attr in attributes) {
+                                               var nv = attr.split ("=", 2);
+                                               if (nv[0] == "hidden") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               hide_param = true;
+                                                       } else if (eval (nv[1]) == "0") {
+                                                               show_param = true;
+                                                       }
+                                               } else if (nv[0] == "is_array") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               param_type.value_owned = true;
+                                                               param_type = new ArrayType (param_type, 1, 
param_type.source_reference);
+                                                               p.variable_type = param_type;
+                                                               if (!out_requested) {
+                                                                       p.direction = ParameterDirection.IN;
+                                                               }
+                                                               array_requested = true;
+                                                       }
+                                               } else if (nv[0] == "is_out") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               p.direction = ParameterDirection.OUT;
+                                                               out_requested = true;
+                                                               if (!array_requested && param_type is 
ArrayType) {
+                                                                       var array_type = (ArrayType) 
param_type;
+                                                                       param_type = array_type.element_type;
+                                                                       p.variable_type = param_type;
+                                                               }
+                                                       }
+                                               } else if (nv[0] == "is_ref") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               p.direction = ParameterDirection.REF;
+                                                               if (!array_requested && param_type is 
ArrayType) {
+                                                                       var array_type = (ArrayType) 
param_type;
+                                                                       param_type = array_type.element_type;
+                                                                       p.variable_type = param_type;
+                                                               }
+                                                       }
+                                               } else if (nv[0] == "takes_ownership") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               param_type.value_owned = true;
+                                                       }
+                                               } else if (nv[0] == "nullable") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               param_type.nullable = true;
+                                                       }
+                                               } else if (nv[0] == "type_arguments") {
+                                                       parse_type_arguments_from_string (param_type, eval 
(nv[1]));
+                                               } else if (nv[0] == "no_array_length") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               p.set_attribute_bool ("CCode", 
"array_length", false);
+                                                       }
+                                               } else if (nv[0] == "array_length_type") {
+                                                       p.set_attribute_string ("CCode", "array_length_type", 
eval (nv[1]));
+                                               } else if (nv[0] == "array_null_terminated") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               p.set_attribute_bool ("CCode", 
"array_length", false);
+                                                               p.set_attribute_bool ("CCode", 
"array_null_terminated", true);
+                                                       }
+                                               } else if (nv[0] == "type_name") {
+                                                       p.variable_type = param_type = parse_type_from_string 
(eval (nv[1]), false);
+                                               }
+                                       }
+                               }
+
+                               if (show_param || !hide_param) {
+                                       cb.add_parameter (p);
+                               }
+                       }
+
+                       remaining_params--;
+               }
+
+               if (suppress_throws == false && error_types != null) {
+                       var type_args = eval (error_types).split (",");
+                       foreach (unowned string type_arg in type_args) {
+                               cb.add_error_type (parse_type_from_string (type_arg, true));
+                       }
+               }
+
+               return cb;
+       }
+
+       private bool is_reference_type (string cname) {
+               var st_attributes = get_attributes (cname);
+               if (st_attributes != null) {
+                       foreach (string attr in st_attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "is_value_type" && eval (nv[1]) == "1") {
+                                       return false;
+                               }
+                       }
+               }
+               return true;
+       }
+
+       private void parse_struct (IdlNodeStruct st_node, Symbol container, IdlModule module) {
+               weak IdlNode node = (IdlNode) st_node;
+               
+               if (st_node.deprecated) {
+                       return;
+               }
+
+               string name = fix_type_name (node.name, container);
+
+               if (!is_reference_type (node.name)) {
+                       var st = container.scope.lookup (name) as Struct;
+                       if (st == null) {
+                               st = new Struct (name, current_source_reference);
+                               st.access = SymbolAccessibility.PUBLIC;
+
+                               var st_attributes = get_attributes (node.name);
+                               if (st_attributes != null) {
+                                       foreach (string attr in st_attributes) {
+                                               var nv = attr.split ("=", 2);
+                                               if (nv[0] == "cheader_filename") {
+                                                       st.set_attribute_string ("CCode", "cheader_filename", 
eval (nv[1]));
+                                               } else if (nv[0] == "hidden") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               return;
+                                                       }
+                                               } else if (nv[0] == "base_type") {
+                                                       st.base_type = parse_type_string (eval (nv[1]));
+                                               } else if (nv[0] == "rank") {
+                                                       st.set_rank (int.parse (eval (nv[1])));
+                                               } else if (nv[0] == "simple_type") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_simple_type (true);
+                                                       }
+                                               } else if (nv[0] == "immutable") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_attribute ("Immutable", true);
+                                                       }
+                                               } else if (nv[0] == "has_type_id") {
+                                                       if (eval (nv[1]) == "0") {
+                                                               st.set_attribute_bool ("CCode", 
"has_type_id", false);
+                                                       }
+                                               } else if (nv[0] == "type_id") {
+                                                       st.set_attribute_string ("CCode", "type_id", eval 
(nv[1]));
+                                               } else if (nv[0] == "has_copy_function") {
+                                                       if (eval (nv[1]) == "0") {
+                                                               st.set_attribute_bool ("CCode", 
"has_copy_function", false);
+                                                       }
+                                               } else if (nv[0] == "deprecated") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_attribute_bool ("Version", 
"deprecated", true);
+                                                       }
+                                               } else if (nv[0] == "replacement") {
+                                                       st.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
+                                               } else if (nv[0] == "deprecated_since") {
+                                                       st.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
+                                               } else if (nv[0] == "has_destroy_function") {
+                                                       if (eval (nv[1]) == "0") {
+                                                               st.set_attribute_bool ("CCode", 
"has_destroy_function", false);
+                                                       }
+                                               } else if (nv[0] == "experimental") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_attribute_bool ("Version", 
"experimental", true);
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               add_symbol_to_container (container, st);
+                               current_source_file.add_node (st);
+                       }
+
+                       current_data_type = st;
+
+                       foreach (weak IdlNode member in st_node.members) {
+                               if (member.type == IdlNodeTypeId.FUNCTION) {
+                                       var m = parse_function ((IdlNodeFunction) member);
+                                       if (m != null) {
+                                               st.add_method (m);
+                                       }
+                               } else if (member.type == IdlNodeTypeId.FIELD) {
+                                       var f = parse_field ((IdlNodeField) member);
+                                       if (f != null) {
+                                               st.add_field (f);
+                                       }
+                               }
+                       }
+
+                       current_data_type = null;
+               } else {
+                       bool ref_function_void = false;
+                       string ref_function = null;
+                       string unref_function = null;
+                       string copy_function = null;
+                       string free_function = null;
+
+                       var cl = container.scope.lookup (name) as Class;
+                       if (cl == null) {
+                               string base_class = null;
+                               bool is_fundamental = false;
+
+                               cl = new Class (name, current_source_reference);
+                               cl.access = SymbolAccessibility.PUBLIC;
+
+                               var cl_attributes = get_attributes (node.name);
+                               if (cl_attributes != null) {
+                                       foreach (string attr in cl_attributes) {
+                                               var nv = attr.split ("=", 2);
+                                               if (nv[0] == "cheader_filename") {
+                                                       cl.set_attribute_string ("CCode", "cheader_filename", 
eval (nv[1]));
+                                               } else if (nv[0] == "base_class") {
+                                                       base_class = eval (nv[1]);
+                                               } else if (nv[0] == "hidden") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               return;
+                                                       }
+                                               } else if (nv[0] == "is_immutable") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               cl.is_immutable = true;
+                                                       }
+                                               } else if (nv[0] == "const_cname") {
+                                                       cl.set_attribute_string ("CCode", "const_cname", eval 
(nv[1]));
+                                               } else if (nv[0] == "is_fundamental") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               is_fundamental = true;
+                                                       }
+                                               } else if (nv[0] == "abstract" && base_class != null) {
+                                                       if (eval (nv[1]) == "1") {
+                                                               cl.is_abstract = true;
+                                                       }
+                                               } else if (nv[0] == "free_function") {
+                                                       free_function = eval (nv[1]);
+                                               } else if (nv[0] == "ref_function") {
+                                                       ref_function = eval (nv[1]);
+                                               } else if (nv[0] == "unref_function") {
+                                                       unref_function = eval (nv[1]);
+                                               } else if (nv[0] == "copy_function") {
+                                                       copy_function = eval (nv[1]);
+                                               } else if (nv[0] == "ref_function_void") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               ref_function_void = true;
+                                                       }
+                                               } else if (nv[0] == "deprecated") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               cl.set_attribute_bool ("Version", 
"deprecated", true);
+                                                       }
+                                               } else if (nv[0] == "replacement") {
+                                                       cl.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
+                                               } else if (nv[0] == "deprecated_since") {
+                                                       cl.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
+                                               } else if (nv[0] == "type_parameters") {
+                                                       foreach (unowned string type_param_name in eval 
(nv[1]).split (",")) {
+                                                               cl.add_type_parameter (new TypeParameter 
(type_param_name, current_source_reference));
+                                                       }
+                                               } else if (nv[0] == "experimental") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               cl.set_attribute_bool ("Version", 
"experimental", true);
+                                                       }
+                                               } else if (nv[0] == "delegate_target_cname") {
+                                                       cl.set_attribute_string ("CCode", 
"delegate_target_cname", eval (nv[1]));
+                                               }
+                                       }
+                               }
+
+                               add_symbol_to_container (container, cl);
+                               current_source_file.add_node (cl);
+
+                               if (base_class != null) {
+                                       var parent = parse_type_string (base_class);
+                                       cl.add_base_type (parent);
+                               }
+                               if (base_class == null && !is_fundamental) {
+                                       cl.is_compact = true;
+                               }
+                       }
+
+                       current_data_type = cl;
+
+                       foreach (weak IdlNode member in st_node.members) {
+                               if (member.type == IdlNodeTypeId.FUNCTION) {
+                                       if ((ref_function == null) && (member.name == "ref")) {
+                                               ref_function = ((IdlNodeFunction) member).symbol;
+                                               ref_function_void = (parse_type (((IdlNodeFunction) 
member).result.type) is VoidType);
+                                       } else if ((unref_function == null) && (member.name == "unref")) {
+                                               unref_function = ((IdlNodeFunction) member).symbol;
+                                       } else if ((free_function == null) && (member.name == "free" || 
member.name == "destroy")) {
+                                               free_function = ((IdlNodeFunction) member).symbol;
+                                       } else {
+                                               if ((copy_function == null) && (member.name == "copy")) {
+                                                       copy_function = ((IdlNodeFunction) member).symbol;
+                                               }
+                                               var m = parse_function ((IdlNodeFunction) member);
+                                               if (m != null) {
+                                                       cl.add_method (m);
+                                               }
+                                       }
+                               } else if (member.type == IdlNodeTypeId.FIELD) {
+                                       var f = parse_field ((IdlNodeField) member);
+                                       if (f != null) {
+                                               cl.add_field (f);
+                                       }
+                               }
+                       }
+
+                       if (ref_function != null) {
+                               cl.set_attribute_string ("CCode", "ref_function", ref_function);
+                               if (ref_function_void) {
+                                       cl.set_attribute_bool ("CCode", "ref_function_void", 
ref_function_void);
+                               }
+                       } else if (copy_function != null) {
+                               cl.set_attribute_string ("CCode", "copy_function", copy_function);
+                       }
+                       if (unref_function != null) {
+                               cl.set_attribute_string ("CCode", "unref_function", unref_function);
+                       } else if (free_function != null && free_function != "%sfree".printf 
(get_lower_case_cprefix (cl))) {
+                               cl.set_attribute_string ("CCode", "free_function", free_function);
+                       }
+
+                       current_data_type = null;
+               }
+       }
+
+       private void parse_union (IdlNodeUnion un_node, Symbol container, IdlModule module) {
+               weak IdlNode node = (IdlNode) un_node;
+               
+               if (un_node.deprecated) {
+                       return;
+               }
+
+               string name = fix_type_name (node.name, container);
+
+               if (!is_reference_type (node.name)) {
+                       var st = container.scope.lookup (name) as Struct;
+                       if (st == null) {
+                               st = new Struct (name, current_source_reference);
+                               st.access = SymbolAccessibility.PUBLIC;
+
+                               var st_attributes = get_attributes (node.name);
+                               if (st_attributes != null) {
+                                       foreach (string attr in st_attributes) {
+                                               var nv = attr.split ("=", 2);
+                                               if (nv[0] == "cheader_filename") {
+                                                       st.set_attribute_string ("CCode", "cheader_filename", 
eval (nv[1]));
+                                               } else if (nv[0] == "deprecated") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_attribute_bool ("Version", 
"deprecated", true);
+                                                       }
+                                               } else if (nv[0] == "replacement") {
+                                                       st.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
+                                               } else if (nv[0] == "deprecated_since") {
+                                                       st.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
+                                               } else if (nv[0] == "hidden") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               return;
+                                                       }
+                                               } else if (nv[0] == "experimental") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_attribute_bool ("Version", 
"experimental", true);
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               add_symbol_to_container (container, st);
+                               current_source_file.add_node (st);
+                       }
+
+                       current_data_type = st;
+
+                       foreach (weak IdlNode member in un_node.members) {
+                               if (member.type == IdlNodeTypeId.FUNCTION) {
+                                       var m = parse_function ((IdlNodeFunction) member);
+                                       if (m != null) {
+                                               st.add_method (m);
+                                       }
+                               } else if (member.type == IdlNodeTypeId.FIELD) {
+                                       var f = parse_field ((IdlNodeField) member);
+                                       if (f != null) {
+                                               st.add_field (f);
+                                       }
+                               }
+                       }
+
+                       current_data_type = null;
+               } else {
+                       var cl = container.scope.lookup (name) as Class;
+                       if (cl == null) {
+                               cl = new Class (name, current_source_reference);
+                               cl.access = SymbolAccessibility.PUBLIC;
+                               cl.is_compact = true;
+
+                               var cl_attributes = get_attributes (node.name);
+                               if (cl_attributes != null) {
+                                       foreach (string attr in cl_attributes) {
+                                               var nv = attr.split ("=", 2);
+                                               if (nv[0] == "cheader_filename") {
+                                                       cl.set_attribute_string ("CCode", "cheader_filename", 
eval (nv[1]));
+                                               } else if (nv[0] == "hidden") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               return;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               add_symbol_to_container (container, cl);
+                               current_source_file.add_node (cl);
+                       }
+
+                       current_data_type = cl;
+
+                       bool ref_function_void = false;
+                       string ref_function = null;
+                       string unref_function = null;
+                       string copy_function = null;
+                       string free_function = null;
+
+                       foreach (weak IdlNode member in un_node.members) {
+                               if (member.type == IdlNodeTypeId.FUNCTION) {
+                                       if (member.name == "ref") {
+                                               ref_function = ((IdlNodeFunction) member).symbol;
+                                               ref_function_void = (parse_type (((IdlNodeFunction) 
member).result.type) is VoidType);
+                                       } else if (member.name == "unref") {
+                                               unref_function = ((IdlNodeFunction) member).symbol;
+                                       } else if (member.name == "free" || member.name == "destroy") {
+                                               free_function = ((IdlNodeFunction) member).symbol;
+                                       } else {
+                                               if (member.name == "copy") {
+                                                       copy_function = ((IdlNodeFunction) member).symbol;
+                                               }
+                                               var m = parse_function ((IdlNodeFunction) member);
+                                               if (m != null) {
+                                                       cl.add_method (m);
+                                               }
+                                       }
+                               } else if (member.type == IdlNodeTypeId.FIELD) {
+                                       var f = parse_field ((IdlNodeField) member);
+                                       if (f != null) {
+                                               cl.add_field (f);
+                                       }
+                               }
+                       }
+
+                       if (ref_function != null) {
+                               cl.set_attribute_string ("CCode", "ref_function", ref_function);
+                               if (ref_function_void) {
+                                       cl.set_attribute_bool ("CCode", "ref_function_void", 
ref_function_void);
+                               }
+                       } else if (copy_function != null) {
+                               cl.set_attribute_string ("CCode", "copy_function", copy_function);
+                       }
+                       if (unref_function != null) {
+                               cl.set_attribute_string ("CCode", "unref_function", unref_function);
+                       } else if (free_function != null && free_function != "%sfree".printf 
(get_lower_case_cprefix (cl))) {
+                               cl.set_attribute_string ("CCode", "free_function", free_function);
+                       }
+
+                       current_data_type = null;
+               }
+       }
+
+       private void parse_boxed (IdlNodeBoxed boxed_node, Symbol container, IdlModule module) {
+               weak IdlNode node = (IdlNode) boxed_node;
+
+               string name = fix_type_name (node.name, container);
+
+               var node_attributes = get_attributes (node.name);
+               if (node_attributes != null) {
+                       foreach (string attr in node_attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "hidden") {
+                                       return;
+                               }
+                       }
+               }
+
+               if (!is_reference_type (node.name)) {
+                       var st = container.scope.lookup (name) as Struct;
+                       if (st == null) {
+                               st = new Struct (name, current_source_reference);
+                               st.access = SymbolAccessibility.PUBLIC;
+
+                               var st_attributes = get_attributes (node.name);
+                               if (st_attributes != null) {
+                                       foreach (string attr in st_attributes) {
+                                               var nv = attr.split ("=", 2);
+                                               if (nv[0] == "cheader_filename") {
+                                                       st.set_attribute_string ("CCode", "cheader_filename", 
eval (nv[1]));
+                                               } else if (nv[0] == "deprecated") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_attribute_bool ("Version", 
"deprecated", true);
+                                                       }
+                                               } else if (nv[0] == "replacement") {
+                                                       st.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
+                                               } else if (nv[0] == "deprecated_since") {
+                                                       st.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
+                                               } else if (nv[0] == "immutable") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_attribute ("Immutable", true);
+                                                       }
+                                               } else if (nv[0] == "has_copy_function") {
+                                                       if (eval (nv[1]) == "0") {
+                                                               st.set_attribute_bool ("CCode", 
"has_copy_function", false);
+                                                       }
+                                               } else if (nv[0] == "has_destroy_function") {
+                                                       if (eval (nv[1]) == "0") {
+                                                               st.set_attribute_bool ("CCode", 
"has_destroy_function", false);
+                                                       }
+                                               } else if (nv[0] == "experimental") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               st.set_attribute_bool ("Version", 
"experimental", true);
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               add_symbol_to_container (container, st);
+                               current_source_file.add_node (st);
+                       }
+               
+                       current_data_type = st;
+
+                       foreach (weak IdlNode member in boxed_node.members) {
+                               if (member.type == IdlNodeTypeId.FUNCTION) {
+                                       var m = parse_function ((IdlNodeFunction) member);
+                                       if (m != null) {
+                                               st.add_method (m);
+                                       }
+                               } else if (member.type == IdlNodeTypeId.FIELD) {
+                                       var f = parse_field ((IdlNodeField) member);
+                                       if (f != null) {
+                                               st.add_field (f);
+                                       }
+                               }
+                       }
+
+                       current_data_type = null;
+               } else {
+                       bool ref_function_void = false;
+                       string ref_function = null;
+                       string unref_function = null;
+                       string copy_function = null;
+                       string free_function = null;
+
+                       var cl = container.scope.lookup (name) as Class;
+                       if (cl == null) {
+                               string base_class = null;
+
+                               cl = new Class (name, current_source_reference);
+                               cl.access = SymbolAccessibility.PUBLIC;
+                               cl.is_compact = true;
+                               if (boxed_node.gtype_init != null) {
+                                       cl.set_attribute_string ("CCode", "type_id", "%s ()".printf 
(boxed_node.gtype_init));
+                               }
+
+                               var cl_attributes = get_attributes (node.name);
+                               if (cl_attributes != null) {
+                                       foreach (string attr in cl_attributes) {
+                                               var nv = attr.split ("=", 2);
+                                               if (nv[0] == "cheader_filename") {
+                                                       cl.set_attribute_string ("CCode", "cheader_filename", 
eval (nv[1]));
+                                               } else if (nv[0] == "base_class") {
+                                                       base_class = eval (nv[1]);
+                                               } else if (nv[0] == "is_immutable") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               cl.is_immutable = true;
+                                                       }
+                                               } else if (nv[0] == "deprecated") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               cl.set_attribute_bool ("Version", 
"deprecated", true);
+                                                       }
+                                               } else if (nv[0] == "replacement") {
+                                                       cl.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
+                                               } else if (nv[0] == "deprecated_since") {
+                                                       cl.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
+                                               } else if (nv[0] == "const_cname") {
+                                                       cl.set_attribute_string ("CCode", "const_cname", eval 
(nv[1]));
+                                               } else if (nv[0] == "free_function") {
+                                                       free_function = eval (nv[1]);
+                                               } else if (nv[0] == "ref_function") {
+                                                       ref_function = eval (nv[1]);
+                                               } else if (nv[0] == "unref_function") {
+                                                       unref_function = eval (nv[1]);
+                                               } else if (nv[0] == "copy_function") {
+                                                       copy_function = eval (nv[1]);
+                                               } else if (nv[0] == "ref_function_void") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               ref_function_void = true;
+                                                       }
+                                               } else if (nv[0] == "experimental") {
+                                                       if (eval (nv[1]) == "1") {
+                                                               cl.set_attribute_bool ("Version", 
"experimental", true);
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               add_symbol_to_container (container, cl);
+                               current_source_file.add_node (cl);
+
+                               if (base_class != null) {
+                                       var parent = parse_type_string (base_class);
+                                       cl.add_base_type (parent);
+                               }
+                       }
+
+                       current_data_type = cl;
+
+                       foreach (weak IdlNode member in boxed_node.members) {
+                               if (member.type == IdlNodeTypeId.FUNCTION) {
+                                       if (member.name == "ref") {
+                                               ref_function = ((IdlNodeFunction) member).symbol;
+                                               ref_function_void = (parse_type (((IdlNodeFunction) 
member).result.type) is VoidType);
+                                       } else if (member.name == "unref") {
+                                               unref_function = ((IdlNodeFunction) member).symbol;
+                                       } else if (member.name == "free" || member.name == "destroy") {
+                                               free_function = ((IdlNodeFunction) member).symbol;
+                                       } else {
+                                               if (member.name == "copy") {
+                                                       copy_function = ((IdlNodeFunction) member).symbol;
+                                               }
+                                               var m = parse_function ((IdlNodeFunction) member);
+                                               if (m != null) {
+                                                       cl.add_method (m);
+                                               }
+                                       }
+                               } else if (member.type == IdlNodeTypeId.FIELD) {
+                                       var f = parse_field ((IdlNodeField) member);
+                                       if (f != null) {
+                                               cl.add_field (f);
+                                       }
+                               }
+                       }
+
+                       if (ref_function != null) {
+                               cl.set_attribute_string ("CCode", "ref_function", ref_function);
+                               if (ref_function_void) {
+                                       cl.set_attribute_bool ("CCode", "ref_function_void", 
ref_function_void);
+                               }
+                       } else if (copy_function != null) {
+                               cl.set_attribute_string ("CCode", "copy_function", copy_function);
+                       }
+                       if (unref_function != null) {
+                               cl.set_attribute_string ("CCode", "unref_function", unref_function);
+                       } else if (free_function != null && free_function != "%sfree".printf 
(get_lower_case_cprefix (cl))) {
+                               cl.set_attribute_string ("CCode", "free_function", free_function);
+                       }
+
+                       current_data_type = null;
+               }
+       }
+       
+       private void parse_enum (IdlNodeEnum en_node, Symbol container, IdlModule module, bool is_flags) {
+               weak IdlNode node = (IdlNode) en_node;
+               string name = fix_type_name (node.name, container);
+               bool existing = true;
+
+               var en = container.scope.lookup (name) as Enum;
+               if (en == null) {
+                       en = new Enum (name, current_source_reference);
+                       en.access = SymbolAccessibility.PUBLIC;
+                       existing = false;
+               } else {
+                       // ignore dummy enum values in -custom.vala files
+                       // they exist for syntactical reasons
+                       var dummy = (EnumValue) en.scope.lookup ("__DUMMY__");
+                       if (dummy != null) {
+                               en.get_values ().remove (dummy);
+                               en.scope.remove ("__DUMMY__");
+                       }
+               }
+
+               if (en_node.gtype_name == null || en_node.gtype_name == "") {
+                       en.set_attribute_bool ("CCode", "has_type_id", false);
+               }
+               
+               string common_prefix = null;
+               
+               foreach (weak IdlNode value in en_node.values) {
+                       var val_attributes = get_attributes (value.name);
+                       bool is_hidden = false;
+                       if (val_attributes != null) {
+                               foreach (string attr in val_attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "hidden" && eval(nv[1]) == "1") {
+                                               is_hidden = true;
+                                       }
+                               }
+                       }
+
+                       if (is_hidden) {
+                               continue;
+                       }
+
+                       if (common_prefix == null) {
+                               common_prefix = value.name;
+                               while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
+                                       // FIXME: could easily be made faster
+                                       common_prefix = common_prefix.substring (0, common_prefix.length - 1);
+                               }
+                       } else {
+                               while (!value.name.has_prefix (common_prefix)) {
+                                       common_prefix = common_prefix.substring (0, common_prefix.length - 1);
+                               }
+                       }
+                       while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
+                              (value.name.get_char (common_prefix.length).isdigit ()) && (value.name.length 
- common_prefix.length) <= 1)) {
+                               // enum values may not consist solely of digits
+                               common_prefix = common_prefix.substring (0, common_prefix.length - 1);
+                       }
+               }
+
+               bool is_errordomain = false;
+
+               string cheader_filename = null;
+
+               var en_attributes = get_attributes (node.name);
+               if (en_attributes != null) {
+                       foreach (string attr in en_attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "common_prefix") {
+                                       common_prefix = eval (nv[1]);
+                               } else if (nv[0] == "cheader_filename") {
+                                       cheader_filename = eval (nv[1]);
+                                       en.set_attribute_string ("CCode", "cheader_filename", 
cheader_filename);
+                               } else if (nv[0] == "hidden") {
+                                       if (eval (nv[1]) == "1") {
+                                               return;
+                                       }
+                               } else if (nv[0] == "deprecated") {
+                                       if (eval (nv[1]) == "1") {
+                                               en.set_attribute_bool ("Version", "deprecated", true);
+                                       }
+                               } else if (nv[0] == "default_value") {
+                                       en.set_attribute_string ("CCode", "default_value", eval (nv[1]));
+                               } else if (nv[0] == "replacement") {
+                                       en.set_attribute_string ("Version", "replacement", eval (nv[1]));
+                               } else if (nv[0] == "deprecated_since") {
+                                       en.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
+                               } else if (nv[0] == "rename_to") {
+                                       en.name = eval (nv[1]);
+                               } else if (nv[0] == "errordomain") {
+                                       if (eval (nv[1]) == "1") {
+                                               is_errordomain = true;
+                                       }
+                               } else if (nv[0] == "to_string") {
+                                       var return_type = new UnresolvedType ();
+                                       return_type.unresolved_symbol = new UnresolvedSymbol (null, "string");
+                                       return_type.value_owned = false;
+                                       var m = new Method ("to_string", return_type, 
current_source_reference);
+                                       m.access = SymbolAccessibility.PUBLIC;
+                                       m.set_attribute_string ("CCode", "cname", eval(nv[1]));
+                                       en.add_method (m);
+                               } else if (nv[0] == "experimental") {
+                                       if (eval (nv[1]) == "1") {
+                                               en.set_attribute_bool ("Version", "experimental", true);
+                                       }
+                               }
+                       }
+               }
+
+               en.set_attribute_string ("CCode", "cprefix", common_prefix);
+               
+               foreach (weak IdlNode value2 in en_node.values) {
+                       EnumValue ev = new EnumValue (value2.name.substring (common_prefix.length), null);
+
+                       var val_attributes = get_attributes (value2.name);
+                       bool is_hidden = false;
+                       if (val_attributes != null) {
+                               foreach (string attr in val_attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "hidden" && eval(nv[1]) == "1") {
+                                               is_hidden = true;
+                                       } else if (nv[0] == "deprecated") {
+                                               if (eval (nv[1]) == "1") {
+                                                       ev.set_attribute_bool ("Version", "deprecated", true);
+                                               }
+                                       }  else if (nv[0] == "replacement") {
+                                               ev.set_attribute_string ("Version", "replacement", eval 
(nv[1]));
+                                       } else if (nv[0] == "deprecated_since") {
+                                               ev.set_attribute_string ("Version", "deprecated_since", eval 
(nv[1]));
+                                       }
+                               }
+                       }
+
+                       if (!is_hidden) {
+                               en.add_value (ev);
+                       }
+               }
+
+               if (is_errordomain) {
+                       var ed = new ErrorDomain (en.name, current_source_reference);
+                       ed.access = SymbolAccessibility.PUBLIC;
+                       ed.set_attribute_string ("CCode", "cprefix", common_prefix);
+
+                       if (cheader_filename != null) {
+                               ed.set_attribute_string ("CCode", "cheader_filename", cheader_filename);
+                       }
+
+                       foreach (EnumValue ev in en.get_values ()) {
+                               ed.add_code (new ErrorCode (ev.name));
+                       }
+
+                       current_source_file.add_node (ed);
+                       if (!existing) {
+                               add_symbol_to_container (container, ed);
+                       }
+               } else {
+                       en.set_attribute ("Flags", is_flags);
+                       current_source_file.add_node (en);
+                       if (!existing) {
+                               add_symbol_to_container (container, en);
+                       }
+               }
+       }
+       
+       private void parse_object (IdlNodeInterface node, Symbol container, IdlModule module) {
+               string name = fix_type_name (((IdlNode) node).name, container);
+
+               string base_class = null;
+
+               var cl = container.scope.lookup (name) as Class;
+               if (cl == null) {
+                       cl = new Class (name, current_source_reference);
+                       cl.access = SymbolAccessibility.PUBLIC;
+                       
+                       var attributes = get_attributes (node.gtype_name);
+                       if (attributes != null) {
+                               foreach (string attr in attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "cheader_filename") {
+                                               cl.set_attribute_string ("CCode", "cheader_filename", eval 
(nv[1]));
+                                       } else if (nv[0] == "base_class") {
+                                               base_class = eval (nv[1]);
+                                       } else if (nv[0] == "hidden") {
+                                               if (eval (nv[1]) == "1") {
+                                                       return;
+                                               }
+                                       } else if (nv[0] == "type_check_function") {
+                                               cl.set_attribute_string ("CCode", "type_check_function", eval 
(nv[1]));
+                                       } else if (nv[0] == "deprecated") {
+                                               if (eval (nv[1]) == "1") {
+                                                       cl.set_attribute_bool ("Version", "deprecated", true);
+                                               }
+                                       } else if (nv[0] == "replacement") {
+                                               cl.set_attribute_string ("Version", "replacement", eval 
(nv[1]));
+                                       } else if (nv[0] == "deprecated_since") {
+                                               cl.set_attribute_string ("Version", "deprecated_since", eval 
(nv[1]));
+                                       } else if (nv[0] == "type_id") {
+                                               cl.set_attribute_string ("CCode", "type_id", eval (nv[1]));
+                                       } else if (nv[0] == "abstract") {
+                                               if (eval (nv[1]) == "1") {
+                                                       cl.is_abstract = true;
+                                               }
+                                       } else if (nv[0] == "experimental") {
+                                               if (eval (nv[1]) == "1") {
+                                                       cl.set_attribute_bool ("Version", "experimental", 
true);
+                                               }
+                                       } else if (nv[0] == "compact") {
+                                               if (eval (nv[1]) == "1") {
+                                                       cl.is_compact = true;
+                                               }
+                                       } else if (nv[0] == "ref_function") {
+                                               cl.set_attribute_string ("CCode", "ref_function", eval 
(nv[1]));
+                                       } else if (nv[0] == "unref_function") {
+                                               cl.set_attribute_string ("CCode", "unref_function", eval 
(nv[1]));
+                                       } else if (nv[0] == "copy_function") {
+                                               cl.set_attribute_string ("CCode", "copy_function", eval 
(nv[1]));
+                                       } else if (nv[0] == "free_function") {
+                                               cl.set_attribute_string ("CCode", "free_function", eval 
(nv[1]));
+                                       }
+                               }
+                       }
+
+                       add_symbol_to_container (container, cl);
+                       current_source_file.add_node (cl);
+               }
+
+               if (base_class != null) {
+                       var parent = parse_type_string (base_class);
+                       cl.add_base_type (parent);
+               } else if (node.parent != null) {
+                       if (!cl.is_compact) {
+                               var parent = parse_type_string (node.parent);
+                               cl.add_base_type (parent);
+                       }
+               } else {
+                       var gobject_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), 
"Object");
+                       cl.add_base_type (new UnresolvedType.from_symbol (gobject_symbol));
+               }
+               
+               foreach (string iface_name in node.interfaces) {
+                       bool skip_iface = false;
+
+                       var attributes = get_attributes (iface_name);
+                       if (attributes != null) {
+                               foreach (string attr in attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "hidden") {
+                                               if (eval (nv[1]) == "1") {
+                                                       skip_iface = true;
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (skip_iface) {
+                               continue;
+                       }
+
+                       var iface = parse_type_string (iface_name);
+                       cl.add_base_type (iface);
+               }
+               
+               current_data_type = cl;
+               
+               current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
+               var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
+               var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
+               
+               foreach (weak IdlNode member in node.members) {
+                       if (member.type == IdlNodeTypeId.FUNCTION) {
+                               current_type_func_map.set (member.name, (IdlNodeFunction) member);
+                       }
+                       if (member.type == IdlNodeTypeId.VFUNC) {
+                               current_type_vfunc_map.set (member.name, "1");
+                       }
+               }
+
+               foreach (weak IdlNode member in node.members) {
+                       if (member.type == IdlNodeTypeId.FUNCTION) {
+                               // Ignore if vfunc (handled below) 
+                               if (!current_type_vfunc_map.contains (member.name)) {
+                                       var m = parse_function ((IdlNodeFunction) member);
+                                       if (m != null) {
+                                               cl.add_method (m);
+                                       }
+                               }
+                       } else if (member.type == IdlNodeTypeId.VFUNC) {
+                               var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get 
(member.name));
+                               if (m != null) {
+                                       cl.add_method (m);
+                               }
+                       } else if (member.type == IdlNodeTypeId.PROPERTY) {
+                               var prop = parse_property ((IdlNodeProperty) member);
+                               if (prop != null) {
+                                       cl.add_property (prop);
+                               }
+                       } else if (member.type == IdlNodeTypeId.SIGNAL) {
+                               var sig = parse_signal ((IdlNodeSignal) member);
+                               if (sig != null) {
+                                       cl.add_signal (sig);
+                               }
+                       }
+               }
+               
+               foreach (weak IdlNode member in node.members) {
+                       if (member.type == IdlNodeTypeId.FIELD) {
+                               if (!current_type_symbol_set.contains (member.name)) {
+                                       var f = parse_field ((IdlNodeField) member);
+                                       if (f != null) {
+                                               cl.add_field (f);
+                                       }
+                               }
+                       }
+               }
+               
+               foreach (Property prop in cl.get_properties ()) {
+                       var getter = "get_%s".printf (prop.name);
+                       
+                       if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
+                               prop.set_attribute ("NoAccessorMethod", true);
+                       }
+                       
+                       var setter = "set_%s".printf (prop.name);
+                       
+                       if (prop.set_accessor != null && prop.set_accessor.writable
+                           && !current_type_symbol_set.contains (setter)) {
+                               prop.set_attribute ("NoAccessorMethod", true);
+                       }
+
+                       if (prop.get_attribute ("NoAccessorMethod") != null && prop.get_accessor != null) {
+                               prop.get_accessor.value_type.value_owned = true;
+                       }
+               }
+
+               handle_async_methods (cl);
+
+               if (cl.default_construction_method == null) {
+                       // always provide constructor in generated bindings
+                       // to indicate that implicit Object () chainup is allowed
+                       var cm = new CreationMethod (null, null, cl.source_reference);
+                       cm.has_construct_function = false;
+                       cm.access = SymbolAccessibility.PROTECTED;
+                       cl.add_method (cm);
+               }
+
+               current_data_type = null;
+               current_type_symbol_set = null;
+       }
+
+       private void parse_interface (IdlNodeInterface node, Symbol container, IdlModule module) {
+               string name = fix_type_name (node.gtype_name, container);
+
+               var iface = container.scope.lookup (name) as Interface;
+               if (iface == null) {
+                       iface = new Interface (name, current_source_reference);
+                       iface.access = SymbolAccessibility.PUBLIC;
+                       
+                       var attributes = get_attributes (node.gtype_name);
+                       if (attributes != null) {
+                               foreach (string attr in attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "cheader_filename") {
+                                               iface.set_attribute_string ("CCode", "cheader_filename", eval 
(nv[1]));
+                                       } else if (nv[0] == "hidden") {
+                                               if (eval (nv[1]) == "1") {
+                                                       return;
+                                               }
+                                       } else if (nv[0] == "type_cname") {
+                                               iface.set_attribute_string ("CCode", "type_cname", eval 
(nv[1]));
+                                       } else if (nv[0] == "lower_case_csuffix") {
+                                               iface.set_attribute_string ("CCode", "lower_case_csuffix", 
eval (nv[1]));
+                                       }
+                               }
+                       }
+                       
+                       foreach (string prereq_name in node.prerequisites) {
+                               var prereq = parse_type_string (prereq_name);
+                               iface.add_prerequisite (prereq);
+                       }
+
+                       add_symbol_to_container (container, iface);
+                       current_source_file.add_node (iface);
+               }
+
+               current_data_type = iface;
+
+               current_type_symbol_set = new HashSet<string> (str_hash, str_equal);
+               var current_type_func_map = new HashMap<string,weak IdlNodeFunction> (str_hash, str_equal);
+               var current_type_vfunc_map = new HashMap<string,string> (str_hash, str_equal);
+
+               foreach (weak IdlNode member in node.members) {
+                       if (member.type == IdlNodeTypeId.FUNCTION) {
+                               current_type_func_map.set (member.name, (IdlNodeFunction) member);
+                       }
+                       if (member.type == IdlNodeTypeId.VFUNC) {
+                               current_type_vfunc_map.set (member.name, "1");
+                       }
+               }
+
+               foreach (weak IdlNode member in node.members) {
+                       if (member.type == IdlNodeTypeId.FUNCTION) {
+                               // Ignore if vfunc (handled below) 
+                               if (!current_type_vfunc_map.contains (member.name)) {
+                                       var m = parse_function ((IdlNodeFunction) member, true);
+                                       if (m != null) {
+                                               iface.add_method (m);
+                                       }
+                               }
+                       } else if (member.type == IdlNodeTypeId.VFUNC) {
+                               var m = parse_virtual ((IdlNodeVFunc) member, current_type_func_map.get 
(member.name), true);
+                               if (m != null) {
+                                       iface.add_method (m);
+                               }
+                       } else if (member.type == IdlNodeTypeId.PROPERTY) {
+                               var prop = parse_property ((IdlNodeProperty) member);
+                               if (prop != null) {
+                                       iface.add_property (prop);
+                               }
+                       } else if (member.type == IdlNodeTypeId.SIGNAL) {
+                               var sig = parse_signal ((IdlNodeSignal) member);
+                               if (sig != null) {
+                                       iface.add_signal (sig);
+                                       sig.is_virtual = false;
+                               }
+                       }
+               }
+
+               foreach (Property prop in iface.get_properties ()) {
+                       var getter = "get_%s".printf (prop.name);
+
+                       if (prop.get_accessor != null && !current_type_symbol_set.contains (getter)) {
+                               prop.set_attribute ("NoAccessorMethod", true);
+                       }
+
+                       var setter = "set_%s".printf (prop.name);
+
+                       if (prop.set_accessor != null && prop.set_accessor.writable
+                           && !current_type_symbol_set.contains (setter)) {
+                               prop.set_attribute ("NoAccessorMethod", true);
+                       }
+
+                       if (prop.get_attribute ("NoAccessorMethod") != null && prop.get_accessor != null) {
+                               prop.get_accessor.value_type.value_owned = true;
+                       }
+               }
+
+               handle_async_methods (iface);
+
+               current_data_type = null;
+       }
+
+       void handle_async_methods (ObjectTypeSymbol type_symbol) {
+               Set<Method> finish_methods = new HashSet<Method> ();
+               var methods = type_symbol.get_methods ();
+
+               foreach (Method m in methods) {
+                       if (m.coroutine) {
+                               string finish_method_base;
+                               if (m.name.has_suffix ("_async")) {
+                                       finish_method_base = m.name.substring (0, m.name.length - 
"_async".length);
+                               } else {
+                                       finish_method_base = m.name;
+                               }
+                               var finish_method = type_symbol.scope.lookup (finish_method_base + "_finish") 
as Method;
+
+                               // check if the method is using non-standard finish method name
+                               if (finish_method == null) {
+                                       var method_cname = get_finish_cname (m);
+                                       foreach (Method method in type_symbol.get_methods ()) {
+                                               if (get_cname (method) == method_cname) {
+                                                       finish_method = method;
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               if (finish_method != null) {
+                                       m.return_type = finish_method.return_type.copy ();
+                                       var a = finish_method.get_attribute ("CCode");
+                                       if (a != null && a.has_argument ("array_length")) {
+                                               m.set_attribute_bool ("CCode", "array_length", a.get_bool 
("array_length"));
+                                       }
+                                       if (a != null && a.has_argument ("array_null_terminated")) {
+                                               m.set_attribute_bool ("CCode", "array_null_terminated", 
a.get_bool ("array_null_terminated"));
+                                       }
+                                       foreach (var param in finish_method.get_parameters ()) {
+                                               if (param.direction == ParameterDirection.OUT) {
+                                                       var async_param = param.copy ();
+                                                       if (m.scope.lookup (param.name) != null) {
+                                                               // parameter name conflict
+                                                               async_param.name += "_out";
+                                                       }
+                                                       m.add_parameter (async_param);
+                                               }
+                                       }
+                                       foreach (DataType error_type in finish_method.get_error_types ()) {
+                                               m.add_error_type (error_type.copy ());
+                                       }
+                                       finish_methods.add (finish_method);
+                               }
+                       }
+               }
+
+               foreach (Method m in finish_methods)
+               {
+                       type_symbol.scope.remove (m.name);
+                       methods.remove (m);
+               }
+       }
+       
+       private DataType? parse_type (IdlNodeType type_node, out ParameterDirection direction = null) {
+               direction = ParameterDirection.IN;
+
+               var type = new UnresolvedType ();
+               if (type_node.tag == TypeTag.VOID) {
+                       if (type_node.is_pointer) {
+                               return new PointerType (new VoidType ());
+                       } else {
+                               return new VoidType ();
+                       }
+               } else if (type_node.tag == TypeTag.BOOLEAN) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "bool");
+               } else if (type_node.tag == TypeTag.INT8) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "char");
+               } else if (type_node.tag == TypeTag.UINT8) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
+               } else if (type_node.tag == TypeTag.INT16) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "int16");
+               } else if (type_node.tag == TypeTag.UINT16) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "uint16");
+               } else if (type_node.tag == TypeTag.INT32) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "int32");
+               } else if (type_node.tag == TypeTag.UINT32) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
+               } else if (type_node.tag == TypeTag.INT64) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
+               } else if (type_node.tag == TypeTag.UINT64) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "uint64");
+               } else if (type_node.tag == TypeTag.INT) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "int");
+               } else if (type_node.tag == TypeTag.UINT) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
+               } else if (type_node.tag == TypeTag.LONG) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "long");
+               } else if (type_node.tag == TypeTag.ULONG) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
+               } else if (type_node.tag == TypeTag.SSIZE) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "ssize_t");
+               } else if (type_node.tag == TypeTag.SIZE) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "size_t");
+               } else if (type_node.tag == TypeTag.FLOAT) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "float");
+               } else if (type_node.tag == TypeTag.DOUBLE) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "double");
+               } else if (type_node.tag == TypeTag.UTF8) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "string");
+               } else if (type_node.tag == TypeTag.FILENAME) {
+                       type.unresolved_symbol = new UnresolvedSymbol (null, "string");
+               } else if (type_node.tag == TypeTag.ARRAY) {
+                       var element_type = parse_type (type_node.parameter_type1);
+                       type = element_type as UnresolvedType;
+                       if (type == null) {
+                               return element_type;
+                       }
+                       element_type.value_owned = true;
+                       return new ArrayType (element_type, 1, element_type.source_reference);
+               } else if (type_node.tag == TypeTag.LIST) {
+                       type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), 
"List");
+               } else if (type_node.tag == TypeTag.SLIST) {
+                       type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), 
"SList");
+               } else if (type_node.tag == TypeTag.HASH) {
+                       type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), 
"HashTable");
+               } else if (type_node.tag == TypeTag.ERROR) {
+                       type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), 
"Error");
+               } else if (type_node.unparsed.has_prefix ("cairo_device_t") || type_node.unparsed.has_prefix 
("cairo_pattern_t") ||
+                   type_node.unparsed.has_prefix ("cairo_surface_t")) {
+                       if (type_node.unparsed.has_prefix ("cairo_device_t")) {
+                               type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
"Cairo"), "Device");
+                       } else if (type_node.unparsed.has_prefix ("cairo_pattern_t")) {
+                               type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
"Cairo"), "Pattern");
+                       } else if (type_node.unparsed.has_prefix ("cairo_surface_t")) {
+                               type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
"Cairo"), "Surface");
+                       }
+                       if (type_node.unparsed.has_suffix ("**")) {
+                               direction = ParameterDirection.OUT;
+                       }
+               } else if (type_node.is_interface) {
+                       var n = type_node.@interface;
+                       
+                       if (n == "") {
+                               return null;
+                       }
+                       
+                       if (n.has_prefix ("const-")) {
+                               n = n.substring ("const-".length);
+                       }
+
+                       if (type_node.is_pointer &&
+                           (n == "gchar" || n == "char")) {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "string");
+                               if (type_node.unparsed.has_suffix ("**")) {
+                                       direction = ParameterDirection.OUT;
+                               }
+                       } else if (n == "gunichar") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "unichar");
+                       } else if (n == "gchar") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "char");
+                       } else if (n == "guchar" || n == "guint8") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "uchar");
+                               if (type_node.is_pointer) {
+                                       type.value_owned = true;
+                                       return new ArrayType (type, 1, type.source_reference);
+                               }
+                       } else if (n == "gushort") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "ushort");
+                       } else if (n == "gshort") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "short");
+                       } else if (n == "gconstpointer" || n == "void") {
+                               return new PointerType (new VoidType ());
+                       } else if (n == "goffset" || n == "off_t") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "int64");
+                       } else if (n == "value_array") {
+                               type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
"GLib"), "ValueArray");
+                       } else if (n == "time_t") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "ulong");
+                       } else if (n == "socklen_t") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "uint32");
+                       } else if (n == "mode_t") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
+                       } else if (n == "gint" || n == "pid_t") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "int");
+                       } else if (n == "unsigned" || n == "unsigned-int") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "uint");
+                       } else if (n == "FILE") {
+                               type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
"GLib"), "FileStream");
+                       } else if (n == "struct") {
+                               return new PointerType (new VoidType ());
+                       } else if (n == "iconv_t") {
+                               return new PointerType (new VoidType ());
+                       } else if (n == "GType") {
+                               type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
"GLib"), "Type");
+                               if (type_node.is_pointer) {
+                                       type.value_owned = true;
+                                       return new ArrayType (type, 1, type.source_reference);
+                               }
+                       } else if (n == "GStrv") {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, "string");
+                               type.value_owned = true;
+                               return new ArrayType (type, 1, type.source_reference);
+                       } else {
+                               var named_type = parse_type_string (n);
+                               type = named_type as UnresolvedType;
+                               if (type == null) {
+                                       return named_type;
+                               }
+                               if (is_simple_type (n)) {
+                                       if (type_node.is_pointer) {
+                                               direction = ParameterDirection.OUT;
+                                       }
+                               } else if (type_node.unparsed.has_suffix ("**")) {
+                                       direction = ParameterDirection.OUT;
+                               }
+                       }
+               } else {
+                       stdout.printf ("%d\n", type_node.tag);
+               }
+               return type;
+       }
+       
+       private bool is_simple_type (string type_name) {
+               var st = cname_type_map[type_name] as Struct;
+               if (st != null && st.is_simple_type ()) {
+                       return true;
+               }
+
+               return false;
+       }
+
+       private DataType parse_type_string (string n) {
+               if (n == "va_list") {
+                       // unsupported
+                       return new PointerType (new VoidType ());
+               }
+
+               var type = new UnresolvedType ();
+
+               var dt = cname_type_map[n];
+               if (dt != null) {
+                       UnresolvedSymbol parent_symbol = null;
+                       if (dt.parent_symbol.name != null) {
+                               parent_symbol = new UnresolvedSymbol (null, dt.parent_symbol.name);
+                       }
+                       type.unresolved_symbol = new UnresolvedSymbol (parent_symbol, dt.name);
+                       return type;
+               }
+
+               var type_attributes = get_attributes (n);
+
+               string ns_name = null;
+
+               if (null != type_attributes) {
+                       foreach (string attr in type_attributes) {
+                               var nv = attr.split ("=", 2);
+
+                               if (nv[0] == "cprefix") {
+                                       type.unresolved_symbol = new UnresolvedSymbol (null, n.substring 
(eval (nv[1]).length));
+                               } else if (nv[0] == "name") {
+                                       type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
+                               } else if (nv[0] == "namespace") {
+                                       ns_name = eval (nv[1]);
+                               } else if (nv[0] == "rename_to") {
+                                       type.unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
+                               }
+                       }
+               }
+
+               if (type.unresolved_symbol != null) {
+                       if (type.unresolved_symbol.name == "pointer") {
+                               return new PointerType (new VoidType ());
+                       }
+                       if (ns_name != null) {
+                               type.unresolved_symbol.inner = new UnresolvedSymbol (null, ns_name);
+                       }
+                       return type;
+               }
+
+               if (n.has_prefix (current_namespace.name)) {
+                       type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
current_namespace.name), n.substring (current_namespace.name.length));
+               } else if (current_namespace.parent_symbol != null && current_namespace.parent_symbol.name != 
null && n.has_prefix (current_namespace.parent_symbol.name)) {
+                       type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
current_namespace.parent_symbol.name), n.substring (current_namespace.parent_symbol.name.length));
+               } else if (n.has_prefix ("G")) {
+                       type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, "GLib"), 
n.substring (1));
+               } else {
+                       var name_parts = n.split (".", 2);
+                       if (name_parts[1] == null) {
+                               type.unresolved_symbol = new UnresolvedSymbol (null, name_parts[0]);
+                       } else {
+                               type.unresolved_symbol = new UnresolvedSymbol (new UnresolvedSymbol (null, 
name_parts[0]), name_parts[1]);
+                       }
+               }
+
+               return type;
+       }
+       
+       private DataType? parse_param (IdlNodeParam param, out ParameterDirection direction = null) {
+               var type = parse_type (param.type, out direction);
+
+               // disable for now as null_ok not yet correctly set
+               // type.non_null = !param.null_ok;
+               
+               return type;
+       }
+
+       private UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? 
source_reference = null) {
+               UnresolvedSymbol? sym = null;
+               foreach (unowned string s in symbol_string.split (".")) {
+                       sym = new UnresolvedSymbol (sym, s, source_reference);
+               }
+               if (sym == null) {
+                       Report.error (source_reference, "a symbol must be specified");
+               }
+               return sym;
+       }
+
+       private bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, 
SourceReference? source_reference = null) {
+               int type_arguments_length = (int) type_arguments.length;
+               GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
+
+               int depth = 0;
+               for (var c = 0 ; c < type_arguments_length ; c++) {
+                       if (type_arguments[c] == '<' || type_arguments[c] == '[') {
+                               depth++;
+                               current.append_unichar (type_arguments[c]);
+                       } else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
+                               depth--;
+                               current.append_unichar (type_arguments[c]);
+                       } else if (type_arguments[c] == ',') {
+                               if (depth == 0) {
+                                       var dt = parse_type_from_string (current.str, true, source_reference);
+                                       if (dt == null) {
+                                               return false;
+                                       }
+                                       parent_type.add_type_argument (dt);
+                                       current.truncate ();
+                               } else {
+                                       current.append_unichar (type_arguments[c]);
+                               }
+                       } else {
+                               current.append_unichar (type_arguments[c]);
+                       }
+               }
+
+               var dt = parse_type_from_string (current.str, true, source_reference);
+               if (dt == null) {
+                       return false;
+               }
+               parent_type.add_type_argument (dt);
+
+               return true;
+       }
+
+       private DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? 
source_reference = null) {
+               if (type_from_string_regex == null) {
+                       try {
+                               type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) 
+)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | 
GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
+                       } catch (GLib.RegexError e) {
+                               GLib.error ("Unable to compile regex: %s", e.message);
+                       }
+               }
+
+               GLib.MatchInfo match;
+               if (!type_from_string_regex.match (type_string, 0, out match)) {
+                       Report.error (source_reference, "unable to parse type");
+                       return null;
+               }
+
+               DataType? type = null;
+
+               var ownership_data = match.fetch (1);
+               var type_name = match.fetch (2);
+               var type_arguments_data = match.fetch (3);
+               var pointers_data = match.fetch (4);
+               var array_data = match.fetch (5);
+               var array_dimension_data = match.fetch (6);
+               var nullable_data = match.fetch (7);
+
+               var nullable = nullable_data != null && nullable_data.length > 0;
+
+               if (ownership_data == null && type_name == "void") {
+                       if (array_data == null && !nullable) {
+                               type = new VoidType (source_reference);
+                               if (pointers_data != null) {
+                                       for (int i=0; i < pointers_data.length; i++) {
+                                               type = new PointerType (type);
+                                       }
+                               }
+                               return type;
+                       } else {
+                               Report.error (source_reference, "invalid void type");
+                               return null;
+                       }
+               }
+
+               bool value_owned = owned_by_default;
+
+               if (ownership_data == "owned") {
+                       value_owned = true;
+               } else if (ownership_data == "unowned") {
+                       value_owned = false;
+               }
+
+               var sym = parse_symbol_from_string (type_name, source_reference);
+               if (sym == null) {
+                       return null;
+               }
+               type = new UnresolvedType.from_symbol (sym, source_reference);
+
+               if (type_arguments_data != null && type_arguments_data.length > 0) {
+                       if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
+                               return null;
+                       }
+               }
+
+               if (pointers_data != null) {
+                       for (int i=0; i < pointers_data.length; i++) {
+                               type = new PointerType (type);
+                       }
+               }
+
+               if (array_data != null && array_data.length > 0) {
+                       type.value_owned = true;
+                       type = new ArrayType (type, array_dimension_data.length + 1, source_reference);
+               }
+
+               type.nullable = nullable;
+               type.value_owned = value_owned;
+               return type;
+       }
+
+       private Method? create_method (string name, string symbol, IdlNodeParam? res, 
GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
+               DataType return_type = null;
+               if (res != null) {
+                       return_type = parse_param (res);
+               }
+               
+               Method m;
+               if (!is_interface && (is_constructor || name.has_prefix ("new"))) {
+                       m = new CreationMethod (null, name, current_source_reference);
+                       m.has_construct_function = false;
+                       if (m.name == "new") {
+                               m.name = null;
+                       } else if (m.name.has_prefix ("new_")) {
+                               m.name = m.name.substring ("new_".length);
+                       }
+                       // For classes, check whether a creation method return type equals to the
+                       // type of the class created. If the types do not match (e.g. in most
+                       // gtk widgets) add an attribute to the creation method indicating the used
+                       // return type.
+                       if (current_data_type is Class && res != null) {
+                               if ("%s*".printf (get_cname (current_data_type)) != res.type.unparsed) {
+                                       m.set_attribute_string ("CCode", "type", res.type.unparsed);
+                               }
+                       }
+               } else {
+                       m = new Method (name, return_type, current_source_reference);
+               }
+               m.access = SymbolAccessibility.PUBLIC;
+
+               if (current_type_symbol_set != null) {
+                       current_type_symbol_set.add (name);
+               }
+               
+               if (current_data_type != null) {
+                       var sig_attributes = get_attributes ("%s::%s".printf (get_cname (current_data_type), 
name));
+                       if (sig_attributes != null) {
+                               foreach (string attr in sig_attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
+                                               return null;
+                                       }
+                               }
+                       }
+               }
+               
+               bool add_ellipsis = false;
+               bool suppress_throws = false;
+               string? error_types = null;
+               Symbol? container = null;
+
+               var attributes = get_attributes (symbol);
+               if (attributes != null) {
+                       foreach (string attr in attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "name") {
+                                       m.name = eval (nv[1]);
+                               } else if (nv[0] == "hidden") {
+                                       if (eval (nv[1]) == "1") {
+                                               return null;
+                                       }
+                               } else if (nv[0] == "ellipsis") {
+                                       if (eval (nv[1]) == "1") {
+                                               add_ellipsis = true;
+                                       }
+                               } else if (nv[0] == "printf_format") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.set_attribute ("PrintfFormat", true);
+                                       }
+                               } else if (nv[0] == "transfer_ownership") {
+                                       if (eval (nv[1]) == "1") {
+                                               return_type.value_owned = true;
+                                       }
+                               } else if (nv[0] == "transfer_container") {
+                                       if (eval (nv[1]) == "1") {
+                                               return_type.value_owned = true;
+                                               if (return_type is ArrayType) {
+                                                       ((ArrayType) return_type).element_type.value_owned = 
false;
+                                               }
+                                       }
+                               } else if (nv[0] == "destroys_instance") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.set_attribute ("DestroysInstance", true, 
m.source_reference);
+                                       }
+                               } else if (nv[0] == "returns_floating_reference") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.set_attribute_bool ("CCode", "returns_floating_reference", 
true);
+                                               m.return_type.value_owned = true;
+                                       }
+                               } else if (nv[0] == "nullable") {
+                                       if (eval (nv[1]) == "1" && !(return_type is VoidType)) {
+                                               return_type.nullable = true;
+                                       }
+                               } else if (nv[0] == "sentinel") {
+                                       m.set_attribute_string ("CCode", "sentinel", eval (nv[1]));
+                               } else if (nv[0] == "is_array") {
+                                       if (eval (nv[1]) == "1") {
+                                               return_type.value_owned = true;
+                                               return_type = new ArrayType (return_type, 1, 
return_type.source_reference);
+                                               m.return_type = return_type;
+                                       }
+                               } else if (nv[0] == "is_pointer") {
+                                       if (eval (nv[1]) == "1") {
+                                               return_type = new PointerType (return_type, 
return_type.source_reference);
+                                               m.return_type = return_type;
+                                       }
+                               } else if (nv[0] == "throws") {
+                                       if (eval (nv[1]) == "0") {
+                                               suppress_throws = true;
+                                       }
+                               } else if (nv[0] == "error_types") {
+                                       error_types = eval (nv[1]);
+                               } else if (nv[0] == "no_array_length") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.set_attribute_bool ("CCode", "array_length", false);
+                                       }
+                               } else if (nv[0] == "array_null_terminated") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.set_attribute_bool ("CCode", "array_length", false);
+                                               m.set_attribute_bool ("CCode", "array_null_terminated", 
true);;
+                                       }
+                               } else if (nv[0] == "array_length_type") {
+                                       m.set_attribute_string ("CCode", "array_length_type", eval (nv[1]));
+                               } else if (nv[0] == "type_name") {
+                                       m.return_type = return_type = parse_type_from_string (eval (nv[1]), 
return_type.value_owned);
+                               } else if (nv[0] == "ctype") {
+                                       m.set_attribute_string ("CCode", "type", eval (nv[1]));
+                               } else if (nv[0] == "type_arguments") {
+                                       parse_type_arguments_from_string (return_type, eval (nv[1]));
+                               } else if (nv[0] == "deprecated") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.set_attribute_bool ("Version", "deprecated", true);
+                                       }
+                               } else if (nv[0] == "replacement") {
+                                       m.set_attribute_string ("Version", "replacement", eval (nv[1]));
+                               } else if (nv[0] == "deprecated_since") {
+                                       m.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
+                               } else if (nv[0] == "cheader_filename") {
+                                       m.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
+                               } else if (nv[0] == "abstract") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.is_abstract = true;
+                                       }
+                               } else if (nv[0] == "virtual") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.is_virtual = true;
+                                       }
+                               } else if (nv[0] == "vfunc_name") {
+                                       m.set_attribute_string ("CCode", "vfunc_name", eval (nv[1]));
+                               } else if (nv[0] == "finish_vfunc_name") {
+                                       m.set_attribute_string ("CCode", "finish_vfunc_name", eval (nv[1]));
+                               } else if (nv[0] == "finish_name") {
+                                       m.set_attribute_string ("CCode", "finish_name", eval (nv[1]));
+                               } else if (nv[0] == "async") {
+                                       if (eval (nv[1]) == "1") {
+                                               // force async function, even if it doesn't end in _async
+                                               m.coroutine = true;
+                                       }
+                               } else if (nv[0] == "parent") {
+                                       container = get_container_from_name (eval (nv[1]));
+                                       var prefix = get_lower_case_cprefix (container);
+                                       if (symbol.has_prefix (prefix)) {
+                                               m.name = symbol.substring (prefix.length);
+                                       }
+                               } else if (nv[0] == "experimental") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.set_attribute_bool ("Version", "experimental", true);
+                                       }
+                               } else if (nv[0] == "simple_generics") {
+                                       if (eval (nv[1]) == "1") {
+                                               m.set_attribute_bool ("CCode", "simple_generics", true);
+                                       }
+                               }
+                       }
+               }
+       
+               bool first = true;
+               Parameter last_param = null;
+               DataType last_param_type = null;
+               foreach (weak IdlNodeParam param in parameters) {
+                       weak IdlNode param_node = (IdlNode) param;
+                       
+                       if (first) {
+                               first = false;
+                               if (!(m is CreationMethod) &&
+                                   current_data_type != null &&
+                                   param.type.is_interface &&
+                                   (param_node.name == "self" ||
+                                    param.type.@interface.has_suffix (get_cname (current_data_type)))) {
+                                       // instance method
+                                       continue;
+                               } else if (!(m is CreationMethod) &&
+                                   current_data_type != null &&
+                                   param.type.is_interface &&
+                                   (param_node.name == "klass" ||
+                                    param.type.@interface.has_suffix ("%sClass".printf(get_cname 
(current_data_type))))) {
+                                       // class method
+                                       m.binding = MemberBinding.CLASS;
+                                       if (m.name.has_prefix ("class_")) {
+                                               m.name = m.name.substring ("class_".length, m.name.length - 
"class_".length);
+                                       }
+                                       continue;
+                               } else {
+                                       // static method
+                                       m.binding = MemberBinding.STATIC;
+                               }
+                       }
+
+                       if (param.type.@interface == "GAsyncReadyCallback" && (symbol.has_suffix ("_async") 
|| m.coroutine)) {
+                               // async method
+                               m.coroutine = true;
+                               continue;
+                       }
+
+                       // check for GError parameter
+                       if (suppress_throws == false && param_is_exception (param)) {
+                               if (error_types == null)
+                                       m.add_error_type (parse_type (param.type));
+                               continue;
+                       }
+
+                       string param_name = param_node.name;
+                       if (param_name == "result") {
+                               // avoid conflict with generated result variable
+                               param_name = "_result";
+                       } else if (param_name == "string") {
+                               // avoid conflict with string type
+                               param_name = "str";
+                       }
+                       ParameterDirection direction;
+                       var param_type = parse_param (param, out direction);
+                       var p = new Parameter (param_name, param_type);
+                       p.direction = direction;
+
+                       bool hide_param = false;
+                       bool show_param = false;
+                       bool set_array_length_pos = false;
+                       double array_length_pos = 0;
+                       bool set_delegate_target_pos = false;
+                       double delegate_target_pos = 0;
+                       bool array_requested = false;
+                       bool out_requested = false;
+                       attributes = get_attributes ("%s.%s".printf (symbol, param_node.name));
+                       if (attributes != null) {
+                               foreach (string attr in attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "is_array") {
+                                               if (eval (nv[1]) == "1") {
+                                                       param_type.value_owned = true;
+                                                       param_type = new ArrayType (param_type, 1, 
param_type.source_reference);
+                                                       p.variable_type = param_type;
+                                                       if (!out_requested) {
+                                                               p.direction = ParameterDirection.IN;
+                                                       }
+                                                       array_requested = true;
+                                               }
+                                       } else if (nv[0] == "is_pointer") {
+                                               if (eval (nv[1]) == "1") {
+                                                       param_type = new PointerType (param_type, 
return_type.source_reference);
+                                                       p.variable_type = param_type;
+                                                       if (!out_requested) {
+                                                               p.direction = ParameterDirection.IN;
+                                                       }
+                                               }
+                                       } else if (nv[0] == "is_out") {
+                                               if (eval (nv[1]) == "1") {
+                                                       p.direction = ParameterDirection.OUT;
+                                                       out_requested = true;
+                                                       if (!array_requested && param_type is ArrayType) {
+                                                               var array_type = (ArrayType) param_type;
+                                                               param_type = array_type.element_type;
+                                                               p.variable_type = param_type;
+                                                       }
+                                               }
+                                       } else if (nv[0] == "is_ref") {
+                                               if (eval (nv[1]) == "1") {
+                                                       p.direction = ParameterDirection.REF;
+                                                       if (!array_requested && param_type is ArrayType) {
+                                                               var array_type = (ArrayType) param_type;
+                                                               param_type = array_type.element_type;
+                                                               p.variable_type = param_type;
+                                                       }
+                                               }
+                                       } else if (nv[0] == "nullable") {
+                                               if (eval (nv[1]) == "1" && !(param_type is VoidType)) {
+                                                       param_type.nullable = true;
+                                               }
+                                       } else if (nv[0] == "transfer_ownership") {
+                                               if (eval (nv[1]) == "1") {
+                                                       param_type.value_owned = true;
+                                               }
+                                       } else if (nv[0] == "takes_ownership") {
+                                               if (eval (nv[1]) == "1") {
+                                                       param_type.value_owned = true;
+                                               }
+                                       } else if (nv[0] == "value_owned") {
+                                               if (eval (nv[1]) == "0") {
+                                                       param_type.value_owned = false;
+                                               } else if (eval (nv[1]) == "1") {
+                                                       param_type.value_owned = true;
+                                               }
+                                       } else if (nv[0] == "hidden") {
+                                               if (eval (nv[1]) == "1") {
+                                                       hide_param = true;
+                                               } else if (eval (nv[1]) == "0") {
+                                                       show_param = true;
+                                               }
+                                       } else if (nv[0] == "no_array_length") {
+                                               if (eval (nv[1]) == "1") {
+                                                       p.set_attribute_bool ("CCode", "array_length", false);
+                                               }
+                                       } else if (nv[0] == "array_length_type") {
+                                               p.set_attribute_string ("CCode", "array_length_type", eval 
(nv[1]));
+                                       } else if (nv[0] == "array_null_terminated") {
+                                               if (eval (nv[1]) == "1") {
+                                                       p.set_attribute_bool ("CCode", "array_length", false);
+                                                       p.set_attribute_bool ("CCode", 
"array_null_terminated", true);
+                                               }
+                                       } else if (nv[0] == "array_length_pos") {
+                                               set_array_length_pos = true;
+                                               array_length_pos = double.parse (eval (nv[1]));
+                                       } else if (nv[0] == "delegate_target_pos") {
+                                               set_delegate_target_pos = true;
+                                               delegate_target_pos = double.parse (eval (nv[1]));
+                                       } else if (nv[0] == "type_name") {
+                                               p.variable_type = param_type = parse_type_from_string (eval 
(nv[1]), false);
+                                       } else if (nv[0] == "ctype") {
+                                               p.set_attribute_string ("CCode", "type", eval (nv[1]));
+                                       } else if (nv[0] == "scope") {
+                                               p.set_attribute_string ("CCode", "scope", eval (nv[1]));
+                                       } else if (nv[0] == "type_arguments") {
+                                               parse_type_arguments_from_string (param_type, eval (nv[1]));
+                                       } else if (nv[0] == "default_value") {
+                                               var val = eval (nv[1]);
+                                               if (val == "null") {
+                                                       p.initializer = new NullLiteral 
(param_type.source_reference);
+                                               } else if (val == "true") {
+                                                       p.initializer = new BooleanLiteral (true, 
param_type.source_reference);
+                                               } else if (val == "false") {
+                                                       p.initializer = new BooleanLiteral (false, 
param_type.source_reference);
+                                               } else if (val == "") {
+                                                       p.initializer = new StringLiteral ("\"\"", 
param_type.source_reference);
+                                               } else {
+                                                       if (int64.try_parse (val)) {
+                                                               p.initializer = new IntegerLiteral (val, 
param_type.source_reference);
+                                                       } else {
+                                                               if (double.try_parse (val)) {
+                                                                       p.initializer = new RealLiteral (val, 
param_type.source_reference);
+                                                               } else {
+                                                                       if (val.has_prefix ("\"") && 
val.has_suffix ("\"")) {
+                                                                               p.initializer = new 
StringLiteral (val, param_type.source_reference);
+                                                                       } else {
+                                                                               foreach (unowned string 
member in val.split (".")) {
+                                                                                       p.initializer = new 
MemberAccess (p.initializer, member, param_type.source_reference);
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (last_param != null && p.name == "n_" + last_param.name) {
+                               if (!(last_param_type is ArrayType)) {
+                                       // last_param is array, p is array length
+                                       last_param_type.value_owned = true;
+                                       last_param_type = new ArrayType (last_param_type, 1, 
last_param_type.source_reference);
+                                       last_param.variable_type = last_param_type;
+                                       last_param.direction = ParameterDirection.IN;
+                               }
+
+                               // hide array length param
+                               hide_param = true;
+                       } else if (last_param != null && p.name == "user_data") {
+                               // last_param is delegate
+
+                               // hide deleate target param
+                               hide_param = true;
+                       }
+
+                       if (show_param || !hide_param) {
+                               m.add_parameter (p);
+                               if (set_array_length_pos) {
+                                       p.set_attribute_double ("CCode", "array_length_pos", 
array_length_pos);
+                               }
+                               if (set_delegate_target_pos) {
+                                       p.set_attribute_double ("CCode", "delegate_target_pos", 
delegate_target_pos);
+                               }
+                       }
+
+                       last_param = p;
+                       last_param_type = param_type;
+               }
+
+               if (suppress_throws == false && error_types != null) {
+                       var type_args = eval (error_types).split (",");
+                       foreach (unowned string type_arg in type_args) {
+                               m.add_error_type (parse_type_from_string (type_arg, true));
+                       }
+               }
+
+               if (first) {
+                       // no parameters => static method
+                       m.binding = MemberBinding.STATIC;
+               }
+
+               if (last_param != null && last_param.name.has_prefix ("first_")) {
+                       last_param.ellipsis = true;
+               } else if (add_ellipsis) {
+                       m.add_parameter (new Parameter.with_ellipsis ());
+               }
+
+               if (container == null) {
+                       container = current_data_type;
+                       if (container == null) {
+                               container = current_namespace;
+                       }
+               }
+               if (symbol != get_cname (m, container)) {
+                       m.set_attribute_string ("CCode", "cname", symbol);
+               }
+               
+               return m;
+       }
+
+       private bool param_is_exception (IdlNodeParam param) {
+               if (!param.type.is_error) {
+                       return false;
+               }
+               var s = param.type.unparsed.chomp ();
+               if (s.has_suffix ("**")) {
+                       return true;
+               }
+               return false;
+       }
+
+       private Method? parse_function (IdlNodeFunction f, bool is_interface = false) {
+               weak IdlNode node = (IdlNode) f;
+               
+               if (f.deprecated) {
+                       return null;
+               }
+       
+               return create_method (node.name, f.symbol, f.result, f.parameters, f.is_constructor, 
is_interface);
+       }
+
+       private Method parse_virtual (IdlNodeVFunc v, IdlNodeFunction? func, bool is_interface = false) {
+               weak IdlNode node = (IdlNode) v;
+               string symbol = "%s%s".printf (get_lower_case_cprefix (current_data_type), node.name);
+
+               if (func != null) {
+                       symbol = func.symbol;
+               }
+
+               Method m = create_method (node.name, symbol, v.result, func != null ? func.parameters : 
v.parameters, false, is_interface);
+               if (m != null) {
+                       m.binding = MemberBinding.INSTANCE;
+                       m.is_virtual = !(m.is_abstract || is_interface);
+                       m.is_abstract = m.is_abstract || is_interface;
+
+                       var attributes = get_attributes (symbol);
+                       if (attributes != null) {
+                               foreach (string attr in attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "virtual") {
+                                               if (eval (nv[1]) == "0") {
+                                                       m.is_virtual = false;
+                                                       m.is_abstract = false;
+                                               } else {
+                                                       m.is_virtual = true;
+                                                       m.is_abstract = false;
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (func == null) {
+                               m.set_attribute ("NoWrapper", true);
+                       }
+               }
+
+               return m;
+       }
+       
+       private string fix_prop_name (string name) {
+               var str = new StringBuilder ();
+               
+               string i = name;
+               
+               while (i.length > 0) {
+                       unichar c = i.get_char ();
+                       if (c == '-') {
+                               str.append_c ('_');
+                       } else {
+                               str.append_unichar (c);
+                       }
+                       
+                       i = i.next_char ();
+               }
+               
+               return str.str;
+       }
+
+       private Property? parse_property (IdlNodeProperty prop_node) {
+               weak IdlNode node = (IdlNode) prop_node;
+               
+               if (prop_node.deprecated) {
+                       return null;
+               }
+               
+               if (!prop_node.readable && !prop_node.writable) {
+                       // buggy GIDL definition
+                       prop_node.readable = true;
+                       prop_node.writable = true;
+               }
+               
+               var prop = new Property (fix_prop_name (node.name), parse_type (prop_node.type), null, null, 
current_source_reference);
+               prop.access = SymbolAccessibility.PUBLIC;
+               prop.interface_only = true;
+
+               if (prop_node.type.is_interface && prop_node.type.interface == "GStrv") {
+                       prop.set_attribute_bool ("CCode", "array_length", false);
+                       prop.set_attribute_bool ("CCode", "array_null_terminated", true);
+               }
+
+               if (prop_node.readable) {
+                       prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy 
(), null, null);
+               }
+               if (prop_node.writable) {
+                       if (prop_node.construct_only) {
+                               prop.set_accessor = new PropertyAccessor (false, false, true, 
prop.property_type.copy (), null, null);
+                       } else {
+                               prop.set_accessor = new PropertyAccessor (false, true, prop_node.@construct, 
prop.property_type.copy (), null, null);
+                       }
+               }
+
+               var attributes = get_attributes ("%s:%s".printf (get_cname (current_data_type), node.name));
+               if (attributes != null) {
+                       foreach (string attr in attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "hidden") {
+                                       if (eval (nv[1]) == "1") {
+                                               return null;
+                                       }
+                               } else if (nv[0] == "type_arguments") {
+                                       parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
+                               } else if (nv[0] == "deprecated") {
+                                       if (eval (nv[1]) == "1") {
+                                               prop.set_attribute_bool ("Version", "deprecated", true);
+                                       }
+                               } else if (nv[0] == "replacement") {
+                                       prop.set_attribute_string ("Version", "replacement", eval (nv[1]));
+                               } else if (nv[0] == "deprecated_since") {
+                                       prop.set_attribute_string ("Version", "deprecated_since", eval 
(nv[1]));
+                               } else if (nv[0] == "accessor_method") {
+                                       if (eval (nv[1]) == "0") {
+                                               prop.set_attribute ("NoAccessorMethod", true);
+                                       }
+                               } else if (nv[0] == "owned_get") {
+                                       if (eval (nv[1]) == "1") {
+                                               prop.get_accessor.value_type.value_owned = true;
+                                       }
+                               } else if (nv[0] == "type_name") {
+                                       prop.property_type = parse_type_from_string (eval (nv[1]), false);
+                               } else if (nv[0] == "experimental") {
+                                       if (eval (nv[1]) == "1") {
+                                               prop.set_attribute_bool ("Version", "experimental", true);
+                                       }
+                               } else if (nv[0] == "nullable") {
+                                       if (eval (nv[1]) == "1" && !(prop.property_type is VoidType)) {
+                                               prop.property_type.nullable = true;
+                                       }
+                               } else if (nv[0] == "abstract") {
+                                       if (eval (nv[1]) == "1") {
+                                               prop.is_abstract = true;
+                                       }
+                               }
+                       }
+               }
+
+               if (current_type_symbol_set != null) {
+                       current_type_symbol_set.add (prop.name);
+               }
+               
+               return prop;
+       }
+
+       private Constant? parse_constant (IdlNodeConstant const_node) {
+               weak IdlNode node = (IdlNode) const_node;
+               
+               var type = parse_type (const_node.type);
+               if (type == null) {
+                       return null;
+               }
+
+               var c = new Constant (node.name, type, null, current_source_reference);
+               c.external = true;
+               
+               string[] attributes = get_attributes (node.name);
+               if (attributes != null) {
+                       foreach (string attr in attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "cheader_filename") {
+                                       c.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
+                               } else if (nv[0] == "deprecated") {
+                                       if (eval (nv[1]) == "1") {
+                                               c.set_attribute_bool ("Version", "deprecated", true);
+                                       }
+                               } else if (nv[0] == "replacement") {
+                                       c.set_attribute_string ("Version", "replacement", eval (nv[1]));
+                               } else if (nv[0] == "deprecated_since") {
+                                       c.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
+                               } else if (nv[0] == "hidden") {
+                                       if (eval (nv[1]) == "1") {
+                                               return null;
+                                       }
+                               } else if (nv[0] == "experimental") {
+                                       if (eval (nv[1]) == "1") {
+                                               c.set_attribute_bool ("Version", "experimental", true);
+                                       }
+                               }
+                       }
+               }
+
+               c.access = SymbolAccessibility.PUBLIC;
+               
+               return c;
+       }
+
+       private Field? parse_field (IdlNodeField field_node) {
+               weak IdlNode node = (IdlNode) field_node;
+               bool unhidden = false;
+
+               var type = parse_type (field_node.type);
+               if (type == null) {
+                       return null;
+               }
+
+               string cheader_filename = null;
+               string ctype = null;
+               string array_length_cname = null;
+               string array_length_type = null;
+               bool array_null_terminated = false;
+               bool deprecated = false;
+               string deprecated_since = null;
+               string replacement = null;
+               bool experimental = false;
+               bool no_delegate_target = false;
+
+               var attributes = get_attributes ("%s.%s".printf (get_cname (current_data_type), node.name));
+               if (attributes != null) {
+                       foreach (string attr in attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "hidden") {
+                                       if (eval (nv[1]) == "1") {
+                                               return null;
+                                       } else {
+                                               unhidden = true;
+                                       }
+                               } else if (nv[0] == "is_array") {
+                                       if (eval (nv[1]) == "1") {
+                                               type.value_owned = true;
+                                               type = new ArrayType (type, 1, type.source_reference);
+                                       }
+                               } else if (nv[0] == "weak") {
+                                       if (eval (nv[1]) == "0") {
+                                               type.value_owned = true;
+                                       }
+                               } else if (nv[0] == "value_owned") {
+                                       if (eval (nv[1]) == "0") {
+                                               type.value_owned = false;
+                                       } else if (eval (nv[1]) == "1") {
+                                               type.value_owned = true;
+                                       }
+                               } else if (nv[0] == "type_name") {
+                                       type = parse_type_from_string (eval (nv[1]), true);
+                               } else if (nv[0] == "type_arguments") {
+                                       parse_type_arguments_from_string (type, eval (nv[1]));
+                               } else if (nv[0] == "deprecated") {
+                                       if (eval (nv[1]) == "1") {
+                                               deprecated = true;
+                                       }
+                               } else if (nv[0] == "replacement") {
+                                       replacement = eval (nv[1]);
+                               } else if (nv[0] == "deprecated_since") {
+                                       deprecated_since = eval (nv[1]);
+                               } else if (nv[0] == "cheader_filename") {
+                                       cheader_filename = eval (nv[1]);
+                               } else if (nv[0] == "ctype") {
+                                       ctype = eval (nv[1]);
+                               } else if (nv[0] == "array_null_terminated") {
+                                       if (eval (nv[1]) == "1") {
+                                               array_null_terminated = true;
+                                       }
+                               } else if (nv[0] == "array_length_cname") {
+                                       array_length_cname = eval (nv[1]);
+                               } else if (nv[0] == "array_length_type") {
+                                       array_length_type = eval (nv[1]);
+                               } else if (nv[0] == "no_delegate_target") {
+                                       if (eval (nv[1]) == "1") {
+                                               no_delegate_target = true;
+                                       }
+                               } else if (nv[0] == "experimental") {
+                                       if (eval (nv[1]) == "1") {
+                                               experimental = true;
+                                       }
+                               }
+                       }
+               }
+
+               if (node.name.has_prefix("_") && !unhidden) {
+                       return null;
+               }
+
+               if (current_type_symbol_set != null) {
+                       current_type_symbol_set.add (node.name);
+               }
+
+               string field_name = node.name;
+               if (field_name == "string") {
+                       // avoid conflict with string type
+                       field_name = "str";
+               }
+
+               var field = new Field (field_name, type, null, current_source_reference);
+               field.access = SymbolAccessibility.PUBLIC;
+
+               if (field_name != node.name) {
+                       field.set_attribute_string ("CCode", "cname", node.name);
+               }
+
+               if (deprecated) {
+                       field.set_attribute_bool ("Version", "deprecated", true);
+
+                       if (deprecated_since != null) {
+                               field.set_attribute_string ("Version", "deprecated_since", deprecated_since);
+                       }
+
+                       if (replacement != null) {
+                               field.set_attribute_string ("Version", "replacement", replacement);
+                       }
+               }
+
+               if (experimental) {
+                       field.set_attribute_bool ("Version", "experimental", true);
+               }
+
+               if (ctype != null) {
+                       field.set_attribute_string ("CCode", "type", ctype);
+               }
+
+               if (cheader_filename != null) {
+                       field.set_attribute_string ("CCode", "cheader_filename", cheader_filename);
+               }
+
+               if (array_null_terminated) {
+                       field.set_attribute_bool ("CCode", "array_null_terminated", true);
+               }
+
+               if (array_length_cname != null || array_length_type != null) {
+                       if (array_length_cname != null) {
+                               field.set_attribute_string ("CCode", "array_length_cname", 
array_length_cname);
+                       }
+                       if (array_length_type != null) {
+                               field.set_attribute_string ("CCode", "array_length_type", array_length_type);
+                       }
+               } else if (field.variable_type is ArrayType) {
+                       field.set_attribute_bool ("CCode", "array_length", false);
+               }
+
+               if (no_delegate_target) {
+                       field.set_attribute_bool ("CCode", "delegate_target", false);
+               }
+
+               return field;
+       }
+
+       private string[]? get_attributes (string codenode) {
+               var attributes = codenode_attributes_map.get (codenode);
+
+               if (attributes == null) {
+                       var dot_required = (-1 != codenode.index_of_char ('.'));
+                       var colon_required = (-1 != codenode.index_of_char (':'));
+
+                       var pattern_specs = codenode_attributes_patterns.get_keys ();
+                       foreach (PatternSpec* pattern in pattern_specs) {
+                               var pspec = codenode_attributes_patterns[pattern];
+
+                               if ((dot_required && -1 == pspec.index_of_char ('.')) ||
+                                   (colon_required && -1 == pspec.index_of_char (':'))) {
+                                       continue;
+                               }
+
+                               if (pattern->match_string (codenode)) {
+                                       return get_attributes (pspec);
+                               }
+                       }
+               }
+
+               if (attributes == null) {
+                       return null;
+               }
+
+               GLib.SList<string> attr_list = new GLib.SList<string> ();
+               var attr = new GLib.StringBuilder.sized (attributes.length);
+               var attributes_len = attributes.length;
+               unowned string remaining = attributes;
+               bool quoted = false, escaped = false;
+               for (int b = 0 ; b < attributes_len ; b++) {
+                       unichar c = remaining.get_char ();
+
+                       if (escaped) {
+                               escaped = false;
+                               attr.append_unichar (c);
+                       } else {
+                               if (c == '"') {
+                                       attr.append_unichar (c);
+                                       quoted = !quoted;
+                               } else if (c == '\\') {
+                                       escaped = true;
+                               } else if (!quoted && (c == ' ')) {
+                                       attr_list.prepend (attr.str);
+                                       attr.truncate (0);
+                               } else {
+                                       attr.append_unichar (c);
+                               }
+                       }
+
+                       remaining = (string) ((char*) remaining + remaining.index_of_nth_char (1));
+               }
+
+               if (attr.len > 0) {
+                       attr_list.prepend (attr.str);
+               }
+
+               var attrs = new string[attr_list.length ()];
+               unowned GLib.SList<string>? attr_i = attr_list;
+               for (int a = 0 ; a < attrs.length ; a++, attr_i = attr_i.next) {
+                       attrs[(attrs.length - 1) - a] = attr_i.data;
+               }
+
+               return attrs;
+       }
+       
+       private string eval (string s) {
+               return ((s.length >= 2) && s.has_prefix ("\"") && s.has_suffix ("\"")) ? s.substring (1, 
s.length - 2) : s;
+       }
+
+       private Signal? parse_signal (IdlNodeSignal sig_node) {
+               weak IdlNode node = (IdlNode) sig_node;
+               
+               if (sig_node.deprecated || sig_node.result == null) {
+                       return null;
+               }
+               
+               var sig = new Signal (fix_prop_name (node.name), parse_param (sig_node.result), 
current_source_reference);
+               sig.access = SymbolAccessibility.PUBLIC;
+               
+               var attributes = get_attributes ("%s::%s".printf (get_cname (current_data_type), sig.name));
+               if (attributes != null) {
+                       string ns_name = null;
+                       foreach (string attr in attributes) {
+                               var nv = attr.split ("=", 2);
+                               if (nv[0] == "name") {
+                                       sig.set_attribute_string ("CCode", "cname", sig.name.replace ("_", 
"-"));
+                                       sig.name = eval (nv[1]);
+                               } else if (nv[0] == "has_emitter" && eval (nv[1]) == "1") {
+                                       sig.set_attribute ("HasEmitter", true);
+                               } else if (nv[0] == "hidden") {
+                                       if (eval (nv[1]) == "1") {
+                                               return null;
+                                       }
+                               } else if (nv[0] == "deprecated") {
+                                       if (eval (nv[1]) == "1") {
+                                               sig.set_attribute_bool ("Version", "deprecated", true);
+                                       }
+                               } else if (nv[0] == "replacement") {
+                                       sig.set_attribute_string ("Version", "replacement", eval (nv[1]));
+                               } else if (nv[0] == "deprecated_since") {
+                                       sig.set_attribute_string ("Version", "deprecated_since", eval 
(nv[1]));
+                               } else if (nv[0] == "transfer_ownership") {
+                                       if (eval (nv[1]) == "1") {
+                                               sig.return_type.value_owned = true;
+                                       }
+                               } else if (nv[0] == "namespace_name") {
+                                       ns_name = eval (nv[1]);
+                               } else if (nv[0] == "type_name") {
+                                       sig.return_type = parse_type_from_string (eval (nv[1]), false);
+                               } else if (nv[0] == "type_arguments") {
+                                       parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
+                               } else if (nv[0] == "experimental") {
+                                       if (eval (nv[1]) == "1") {
+                                               sig.set_attribute_bool ("Version", "experimental", true);
+                                       }
+                               }
+                       }
+                       if (ns_name != null) {
+                               ((UnresolvedType) sig.return_type).unresolved_symbol.inner = new 
UnresolvedSymbol (null, ns_name);
+                       }
+               }
+
+               sig.is_virtual = true;
+
+               bool first = true;
+               
+               foreach (weak IdlNodeParam param in sig_node.parameters) {
+                       if (first) {
+                               // ignore implicit first signal parameter (sender)
+                               first = false;
+                               continue;
+                       }
+               
+                       weak IdlNode param_node = (IdlNode) param;
+                       
+                       ParameterDirection direction;
+                       var param_type = parse_param (param, out direction);
+                       var p = new Parameter (param_node.name, param_type);
+                       p.direction = direction;
+
+                       bool hide_param = false;
+                       bool show_param = false;
+                       attributes = get_attributes ("%s::%s.%s".printf (get_cname (current_data_type), 
sig.name, param_node.name));
+                       if (attributes != null) {
+                               string ns_name = null;
+                               foreach (string attr in attributes) {
+                                       var nv = attr.split ("=", 2);
+                                       if (nv[0] == "hidden") {
+                                               if (eval (nv[1]) == "1") {
+                                                       hide_param = true;
+                                               } else if (eval (nv[1]) == "0") {
+                                                       show_param = true;
+                                               }
+                                       } else if (nv[0] == "is_array") {
+                                               if (eval (nv[1]) == "1") {
+                                                       param_type.value_owned = true;
+                                                       param_type = new ArrayType (param_type, 1, 
param_type.source_reference);
+                                                       p.variable_type = param_type;
+                                                       p.direction = ParameterDirection.IN;
+                                               }
+                                       } else if (nv[0] == "no_array_length") {
+                                               if (eval (nv[1]) == "1") {
+                                                       p.set_attribute_bool ("CCode", "array_length", false);
+                                               }
+                                       } else if (nv[0] == "array_length_type") {
+                                               p.set_attribute_string ("CCode", "array_length_type", nv[1]);
+                                       } else if (nv[0] == "array_null_terminated") {
+                                               if (eval (nv[1]) == "1") {
+                                                       p.set_attribute_bool ("CCode", "array_length", false);
+                                                       p.set_attribute_bool ("CCode", 
"array_null_terminated", true);
+                                               }
+                                       } else if (nv[0] == "is_out") {
+                                               if (eval (nv[1]) == "1") {
+                                                       p.direction = ParameterDirection.OUT;
+                                               }
+                                       } else if (nv[0] == "is_ref") {
+                                               if (eval (nv[1]) == "1") {
+                                                       p.direction = ParameterDirection.REF;
+                                               }
+                                       } else if (nv[0] == "nullable") {
+                                               if (eval (nv[1]) == "1" && !(param_type is VoidType)) {
+                                                       param_type.nullable = true;
+                                               }
+                                       } else if (nv[0] == "transfer_ownership") {
+                                               if (eval (nv[1]) == "1") {
+                                                       param_type.value_owned = true;
+                                               }
+                                       } else if (nv[0] == "type_name") {
+                                               p.variable_type = param_type = parse_type_from_string (eval 
(nv[1]), false);
+                                       } else if (nv[0] == "type_arguments") {
+                                               parse_type_arguments_from_string (p.variable_type, eval 
(nv[1]));
+                                       } else if (nv[0] == "namespace_name") {
+                                               ns_name = eval (nv[1]);
+                                       }
+                               }
+                               if (ns_name != null) {
+                                       ((UnresolvedType) param_type).unresolved_symbol.inner = new 
UnresolvedSymbol (null, ns_name);
+                               }
+                       }
+
+                       if (show_param || !hide_param) {
+                               sig.add_parameter (p);
+                       }
+               }
+               
+               return sig;
+       }
+}
+
+// vim:sw=8 noet
diff --git a/dbusgen/valavapicheck.vala b/dbusgen/valavapicheck.vala
new file mode 100644
index 0000000..ce6340f
--- /dev/null
+++ b/dbusgen/valavapicheck.vala
@@ -0,0 +1,180 @@
+/* valavapicheck.vala
+ *
+ * Copyright (C) 2007  Mathias Hasselmann
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Mathias Hasselmann <mathias hasselmann gmx de>
+ */
+
+using GLib;
+
+class Vala.VAPICheck {
+       public VAPICheck (string gidlname, CodeContext context = new CodeContext ()) {
+               gidl = new SourceFile (context, SourceFileType.SOURCE, gidlname);
+               metadata = new SourceFile (context, SourceFileType.SOURCE, gidlname.substring (0, 
gidlname.length - 5) + ".metadata");
+               this.context = context;
+       }
+
+       public CodeContext context { get; private set; }
+       public SourceFile gidl { get; private set; }
+       public SourceFile metadata { get; private set; }
+
+       private List<string> _scope;
+       private Set<string> _symbols;
+
+       private void parse_gidl () {
+               _scope = new ArrayList<string> ();
+               _symbols = new HashSet<string> (str_hash, str_equal);
+
+               try {
+                       foreach (weak IdlModule module in Idl.parse_file (gidl.filename)) {
+                               parse_members (module.name, module.entries);
+                       }
+               } catch (MarkupError e) {
+                       stderr.printf ("%s: %s\n", gidl.filename, e.message);
+                }
+       }
+
+       private void add_symbol (string name, string? separator = null) {
+
+               if (null != separator) {
+                       string fullname = get_scope () + separator + name;
+                       _symbols.add (fullname);
+               } else {
+                       _symbols.add (name);
+               }
+       }
+
+       private string get_scope () {
+               return _scope[_scope.size - 1];
+       }
+
+       private void enter_scope (string name) {
+               _scope.add (name);
+               add_symbol (name);
+       }
+
+       private void leave_scope () {
+               _scope.remove_at (_scope.size - 1);
+       }
+
+       private void parse_members (string name, GLib.List<IdlNode> members) {
+               enter_scope (name);
+
+               foreach (weak IdlNode node in members) {
+                       switch (node.type) {
+                               case IdlNodeTypeId.ENUM:
+                                       parse_members (((IdlNodeEnum) node).gtype_name,
+                                                                  ((IdlNodeEnum) node).values);
+                                       break;
+
+                               case IdlNodeTypeId.FUNCTION:
+                                       parse_members (((IdlNodeFunction) node).symbol,
+                                                                  (GLib.List<IdlNode>) ((IdlNodeFunction) 
node).parameters);
+                                       break;
+
+                               case IdlNodeTypeId.BOXED:
+                                       parse_members (((IdlNodeBoxed) node).gtype_name,
+                                                                  ((IdlNodeBoxed) node).members);
+                                       break;
+
+                               case IdlNodeTypeId.INTERFACE:
+                               case IdlNodeTypeId.OBJECT:
+                                       parse_members (((IdlNodeInterface) node).gtype_name,
+                                                                  ((IdlNodeInterface) node).members);
+                                       break;
+
+                               case IdlNodeTypeId.FIELD:
+                               case IdlNodeTypeId.PARAM:
+                                       add_symbol (node.name, ".");
+                                       break;
+
+                               case IdlNodeTypeId.PROPERTY:
+                               case IdlNodeTypeId.SIGNAL:
+                                       add_symbol (node.name, "::");
+                                       break;
+
+                               case IdlNodeTypeId.STRUCT:
+                                       parse_members (node.name, ((IdlNodeStruct) node).members);
+                                       break;
+
+                               case IdlNodeTypeId.VALUE:
+                               case IdlNodeTypeId.VFUNC:
+                                       // Not appliable?
+                                       break;
+
+                               default:
+                                       warning ("TODO: %s: Implement support for type %d nodes", node.name, 
node.type);
+                                       break;
+                       }
+               }
+
+               leave_scope ();
+       }
+
+       private int check_metadata () {
+               try {
+                       var metafile = new IOChannel.file (metadata.filename, "r");
+                       string line;
+                       int lineno = 1;
+
+                       while (IOStatus.NORMAL == metafile.read_line (out line, null, null)) {
+                               var tokens = line.split (" ", 2);
+                               var symbol = tokens[0];
+
+                               if (symbol.length > 0 && !_symbols.contains (symbol)) {
+                                       var src = new SourceReference (metadata, SourceLocation (null, 
lineno, 1), SourceLocation (null, lineno, (int)symbol.length));
+                                       Report.error (src, "Symbol `%s' not found".printf (symbol));
+                               }
+
+                               lineno += 1;
+                       }
+
+                       return 0;
+               } catch (Error error) {
+                       Report.error (null, "%s: %s".printf (metadata.filename, error.message));
+                       return 1;
+               }
+       }
+
+       public int run () {
+               if (!FileUtils.test (gidl.filename, FileTest.IS_REGULAR)) {
+                       Report.error (null, "%s not found".printf (gidl.filename));
+                       return 2;
+               }
+
+               if (!FileUtils.test (metadata.filename, FileTest.IS_REGULAR)) {
+                       Report.error (null, "%s not found".printf (metadata.filename));
+                       return 2;
+               }
+
+               parse_gidl ();
+
+               return check_metadata ();
+       }
+
+       static int main (string[] args) {
+               if (2 != args.length || !args[1].has_suffix (".gidl")) {
+                       stdout.printf ("Usage: %s library.gidl\n",
+                                      Path.get_basename (args[0]));
+                       return 2;
+               }
+
+               var vapicheck = new VAPICheck (args[1]);
+               return vapicheck.run ();
+       }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]