adding vapicheck as tool to verify Vala bindings. currently only .metadata
authorMathias Hasselmann <mathias.hasselmann@gmx.de>
Sun, 2 Sep 2007 10:12:06 +0000 (10:12 +0000)
committerMathias Hasselmann <hasselmm@src.gnome.org>
Sun, 2 Sep 2007 10:12:06 +0000 (10:12 +0000)
2007-09-02  Mathias Hasselmann  <mathias.hasselmann@gmx.de>

* vapigen/Makefile.am, vapigen/valavapicheck.vala: adding vapicheck
as tool to verify Vala bindings. currently only .metadata files are
checked for unresolved symbols.

svn path=/trunk/; revision=573

ChangeLog
vapigen/Makefile.am
vapigen/valavapicheck.vala [new file with mode: 0644]

index ddc5ce0..396770b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2007-09-02  Mathias Hasselmann  <mathias.hasselmann@gmx.de>
 
+       * vapigen/Makefile.am, vapigen/valavapicheck.vala: adding vapicheck 
+       as tool to verify Vala bindings. currently only .metadata files are
+       checked for unresolved symbols.
+
+2007-09-02  Mathias Hasselmann  <mathias.hasselmann@gmx.de>
+
        * vapi/packages/gtksourceview-2.0/gtksourceview-2.0.gidl,
          vapi/packages/gtksourceview-2.0/gtksourceview-2.0.metadata,
          vapi/gtksourceview-2.0.vala: regenerated for release 1.90.4
index e191a35..f03a121 100644 (file)
@@ -11,9 +11,10 @@ INCLUDES = \
 
 bin_PROGRAMS = \
        vapigen \
+       vapicheck \
        $(NULL)
 
-BUILT_SOURCES = vapigen.vala.stamp
+BUILT_SOURCES = vapigen.vala.stamp vapicheck.vala.stamp
 
 vapigen_SOURCES = \
        vapigen.vala.stamp \
@@ -25,12 +26,31 @@ vapigen_SOURCES = \
        valavapigen.vala \
        $(NULL)
 
+vapicheck_SOURCES = \
+       vapicheck.vala.stamp \
+       valavapicheck.c \
+       valavapicheck.h \
+       valavapicheck.vala \
+       $(NULL)
+
 vapigen.vala.stamp: $(filter %.vala,$(vapigen_SOURCES))
        $(VALAC) --vapidir $(srcdir)/../vapi --vapidir ../gee --pkg gee --vapidir ../ccode --pkg ccode --vapidir ../vala --pkg vala --vapidir ../gobject-introspection --pkg gidl --pkg config $^
        touch $@
 
+vapicheck.vala.stamp: $(filter %.vala,$(vapicheck_SOURCES))
+       $(VALAC) --vapidir $(srcdir)/../vapi --vapidir ../gee --pkg gee --vapidir ../ccode --pkg ccode --vapidir ../vala --pkg vala --vapidir ../gobject-introspection --pkg gidl --pkg config $^
+       touch $@
+
 vapigen_LDADD = \
        $(GLIB_LIBS) \
+       ../gee/libgee.la \
+       ../gobject/libvala.la \
+       ../gobject-introspection/libgidl.la \
+       $(NULL)
+
+vapicheck_LDADD = \
+       $(GLIB_LIBS) \
+       ../gee/libgee.la \
        ../gobject/libvala.la \
        ../gobject-introspection/libgidl.la \
        $(NULL)
diff --git a/vapigen/valavapicheck.vala b/vapigen/valavapicheck.vala
new file mode 100644 (file)
index 0000000..fc4f56d
--- /dev/null
@@ -0,0 +1,176 @@
+/* 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 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 : Object {
+       public VAPICheck (string! gidlname, construct CodeContext! context = new CodeContext ()) {
+               gidl = new SourceFile (context, gidlname);
+               metadata = new SourceFile (context, gidlname.substring (0, gidlname.len () - 5) + ".metadata");
+       }
+
+       public CodeContext! context { get; construct; }
+       public SourceFile! gidl { get; construct; }
+       public SourceFile! metadata { get; construct; }
+
+       private Gee.List<string> _scope;
+       private Gee.Set<string> _symbols;
+
+       private void parse_gidl () {
+               _scope = new Gee.ArrayList<string> ();
+               _symbols = new Gee.HashSet<string> (str_hash, str_equal);
+
+               foreach (weak IdlModule module in Idl.parse_file (gidl.filename)) {
+                       parse_members (module.name, module.entries);
+               }
+
+       }
+
+       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, 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,
+                                                                  ((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 = null;
+                       int lineno = 1;
+
+                       while (IOStatus.NORMAL == metafile.read_line (out line, null, null)) {
+                               var tokens = line.split (" ", 2);
+                               var symbol = tokens[0];
+
+                               if (symbol.size () > 0 && !_symbols.contains (symbol)) {
+                                       var src = new SourceReference (metadata, lineno, 1, lineno, (int)symbol.len ());
+                                       Report.error (src, "Symbol `%s' not found".printf (symbol));
+                               }
+
+                               lineno += 1;
+                       }
+
+                       return 0;
+               } catch (FileError 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 ();
+       }
+}