[vala/wip/dbusgen: 1/6] first commit of dbusgen
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/dbusgen: 1/6] first commit of dbusgen
- Date: Thu, 23 Nov 2017 14:58:36 +0000 (UTC)
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]