vala r1854 - in trunk: . vapigen
- From: juergbi svn gnome org
- To: svn-commits-list gnome org
- Subject: vala r1854 - in trunk: . vapigen
- Date: Fri, 17 Oct 2008 13:41:33 +0000 (UTC)
Author: juergbi
Date: Fri Oct 17 13:41:33 2008
New Revision: 1854
URL: http://svn.gnome.org/viewvc/vala?rev=1854&view=rev
Log:
2008-10-17 JÃrg Billeter <j bitron ch>
* vapigen/Makefile.am:
* vapigen/valagirparser.vala:
* vapigen/valamarkupreader.vala:
* vapigen/valavapigen.vala:
Add experimental .gir support to vapigen
Added:
trunk/vapigen/valagirparser.vala
trunk/vapigen/valamarkupreader.vala
Modified:
trunk/ChangeLog
trunk/vapigen/Makefile.am
trunk/vapigen/valavapigen.vala
Modified: trunk/vapigen/Makefile.am
==============================================================================
--- trunk/vapigen/Makefile.am (original)
+++ trunk/vapigen/Makefile.am Fri Oct 17 13:41:33 2008
@@ -21,6 +21,8 @@
vapigen_VALASOURCES = \
valagidlparser.vala \
+ valagirparser.vala \
+ valamarkupreader.vala \
valavapigen.vala \
$(NULL)
Added: trunk/vapigen/valagirparser.vala
==============================================================================
--- (empty file)
+++ trunk/vapigen/valagirparser.vala Fri Oct 17 13:41:33 2008
@@ -0,0 +1,769 @@
+/* valagirparser.vala
+ *
+ * Copyright (C) 2008 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:
+ * JÃrg Billeter <j bitron ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Code visitor parsing all Vala source files.
+ */
+public class Vala.GirParser : CodeVisitor {
+ MarkupReader reader;
+
+ CodeContext context;
+
+ SourceFile current_source_file;
+ SourceLocation begin;
+ SourceLocation end;
+ MarkupTokenType current_token;
+
+ HashMap<string,string> attributes_map = new HashMap<string,string> (str_hash, str_equal);
+
+ /**
+ * Parses all .gir source files in the specified code
+ * context and builds a code tree.
+ *
+ * @param context a code context
+ */
+ public void parse (CodeContext context) {
+ this.context = context;
+ context.accept (this);
+ }
+
+ public override void visit_source_file (SourceFile source_file) {
+ if (source_file.filename.has_suffix (".gir")) {
+ parse_file (source_file);
+ }
+ }
+
+ public void parse_file (SourceFile source_file) {
+ this.current_source_file = source_file;
+ reader = new MarkupReader (source_file.filename);
+
+ // xml prolog
+ next ();
+ next ();
+
+ next ();
+ parse_repository ();
+
+ reader = null;
+ this.current_source_file = null;
+ }
+
+ void next () {
+ current_token = reader.read_token (out begin, out end);
+ }
+
+ void start_element (string name) {
+ if (current_token != MarkupTokenType.START_ELEMENT || reader.name != name) {
+ // error
+ Report.error (get_current_src (), "expected start element of `%s'".printf (name));
+ }
+ }
+
+ void end_element (string name) {
+ if (current_token != MarkupTokenType.END_ELEMENT || reader.name != name) {
+ // error
+ Report.error (get_current_src (), "expected end element of `%s'".printf (name));
+ }
+ next ();
+ }
+
+ SourceReference get_current_src () {
+ return new SourceReference (this.current_source_file, begin.line, begin.column, end.line, end.column);
+ }
+
+ void parse_repository () {
+ start_element ("repository");
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ if (reader.name == "namespace") {
+ context.root.add_namespace (parse_namespace ());
+ } else if (reader.name == "include") {
+ parse_include ();
+ } else {
+ // error
+ Report.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader.name));
+ break;
+ }
+ }
+ end_element ("repository");
+ }
+
+ void parse_include () {
+ start_element ("include");
+ next ();
+ end_element ("include");
+ }
+
+ Namespace parse_namespace () {
+ start_element ("namespace");
+ var ns = new Namespace (reader.get_attribute ("name"));
+ string cheader = get_attribute (ns.name, "c:header-filename");
+ if (cheader != null) {
+ ns.set_cheader_filename (cheader);
+ }
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ Symbol sym = null;
+ if (reader.name == "alias") {
+ sym = parse_alias ();
+ } else if (reader.name == "enumeration") {
+ sym = parse_enumeration ();
+ } else if (reader.name == "bitfield") {
+ sym = parse_bitfield ();
+ } else if (reader.name == "function") {
+ sym = parse_function ();
+ } else if (reader.name == "callback") {
+ sym = parse_callback ();
+ } else if (reader.name == "record") {
+ sym = parse_record ();
+ } else if (reader.name == "class") {
+ sym = parse_class ();
+ } else if (reader.name == "interface") {
+ sym = parse_interface ();
+ } else if (reader.name == "glib:boxed") {
+ parse_boxed ();
+ } else if (reader.name == "union") {
+ parse_union ();
+ } else if (reader.name == "constant") {
+ sym = parse_constant ();
+ } else {
+ // error
+ Report.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader.name));
+ break;
+ }
+
+ if (sym is Class) {
+ ns.add_class ((Class) sym);
+ } else if (sym is Interface) {
+ ns.add_interface ((Interface) sym);
+ } else if (sym is Struct) {
+ ns.add_struct ((Struct) sym);
+ } else if (sym is Enum) {
+ ns.add_enum ((Enum) sym);
+ } else if (sym is Delegate) {
+ ns.add_delegate ((Delegate) sym);
+ } else if (sym is Method) {
+ ns.add_method ((Method) sym);
+ } else if (sym is Constant) {
+ ns.add_constant ((Constant) sym);
+ } else if (sym == null) {
+ continue;
+ }
+ current_source_file.add_node (sym);
+ }
+ end_element ("namespace");
+ return ns;
+ }
+
+ Struct parse_alias () {
+ start_element ("alias");
+ var st = new Struct (reader.get_attribute ("name"));
+ st.access = SymbolAccessibility.PUBLIC;
+ st.add_base_type (parse_type_from_name (reader.get_attribute ("target")));
+ next ();
+ end_element ("alias");
+ return st;
+ }
+
+ Enum parse_enumeration () {
+ start_element ("enumeration");
+ var en = new Enum (reader.get_attribute ("name"));
+ en.access = SymbolAccessibility.PUBLIC;
+ next ();
+
+ string common_prefix = null;
+
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ if (reader.name == "member") {
+ var ev = parse_enumeration_member ();
+ en.add_value (ev);
+
+ string cname = ev.get_cname ();
+
+ if (common_prefix == null) {
+ common_prefix = cname;
+ while (common_prefix.len () > 0 && !common_prefix.has_suffix ("_")) {
+ // FIXME: could easily be made faster
+ common_prefix = common_prefix.ndup (common_prefix.size () - 1);
+ }
+ } else {
+ while (!cname.has_prefix (common_prefix)) {
+ common_prefix = common_prefix.ndup (common_prefix.size () - 1);
+ }
+ }
+ while (common_prefix.len () > 0 && (!common_prefix.has_suffix ("_") ||
+ (cname.offset (common_prefix.size ()).get_char ().isdigit ()) && (cname.len () - common_prefix.len ()) <= 1)) {
+ // enum values may not consist solely of digits
+ common_prefix = common_prefix.ndup (common_prefix.size () - 1);
+ }
+ } else {
+ // error
+ break;
+ }
+ }
+
+ en.set_cprefix (common_prefix);
+
+ end_element ("enumeration");
+ return en;
+ }
+
+ Enum parse_bitfield () {
+ start_element ("bitfield");
+ var en = new Enum (reader.get_attribute ("name"));
+ en.access = SymbolAccessibility.PUBLIC;
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ if (reader.name == "member") {
+ en.add_value (parse_enumeration_member ());
+ } else {
+ // error
+ break;
+ }
+ }
+ end_element ("bitfield");
+ return en;
+ }
+
+ EnumValue parse_enumeration_member () {
+ start_element ("member");
+ var ev = new EnumValue (string.joinv ("_", reader.get_attribute ("name").up ().split ("-")));
+ ev.set_cname (reader.get_attribute ("c:identifier"));
+ next ();
+ end_element ("member");
+ return ev;
+ }
+
+ Method parse_function () {
+ start_element ("function");
+ string name = reader.get_attribute ("name");
+ next ();
+ DataType return_type;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
+ return_type = parse_return_value ();
+ } else {
+ return_type = new VoidType ();
+ }
+ var m = new Method (name, return_type);
+ m.access = SymbolAccessibility.PUBLIC;
+ m.binding = MemberBinding.STATIC;
+ var parameters = new ArrayList<FormalParameter> ();
+ var array_length_parameters = new ArrayList<int> ();
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+ start_element ("parameters");
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ int array_length_idx = -1;
+ var param = parse_parameter (out array_length_idx);
+ if (array_length_idx != -1) {
+ array_length_parameters.add (array_length_idx);
+ }
+ parameters.add (param);
+ }
+ end_element ("parameters");
+ }
+ int i = 0;
+ foreach (FormalParameter param in parameters) {
+ if (!array_length_parameters.contains (i)) {
+ m.add_parameter (param);
+ }
+ i++;
+ }
+ end_element ("function");
+ return m;
+ }
+
+ DataType parse_return_value () {
+ start_element ("return-value");
+ string transfer = reader.get_attribute ("transfer-ownership");
+ next ();
+ var type = parse_type ();
+ if (transfer == "full") {
+ type.value_owned = true;
+ }
+ end_element ("return-value");
+ return type;
+ }
+
+ FormalParameter parse_parameter (out int array_length_idx = null) {
+ FormalParameter param = null;
+
+ start_element ("parameter");
+ string name = reader.get_attribute ("name");
+ string direction = reader.get_attribute ("direction");
+ string transfer = reader.get_attribute ("transfer-ownership");
+ next ();
+ if (reader.name == "varargs") {
+ start_element ("varargs");
+ next ();
+ param = new FormalParameter.with_ellipsis ();
+ end_element ("varargs");
+ } else {
+ var type = parse_type (out array_length_idx);
+ if (transfer == "full") {
+ type.value_owned = true;
+ }
+ param = new FormalParameter (name, type);
+ if (direction == "out") {
+ param.direction = ParameterDirection.OUT;
+ } else if (direction == "inout") {
+ param.direction = ParameterDirection.REF;
+ }
+ }
+ end_element ("parameter");
+ return param;
+ }
+
+ DataType parse_type (out int array_length_index = null) {
+ if (reader.name == "array") {
+ start_element ("array");
+ if (reader.get_attribute ("length") != null
+ && &array_length_index != null) {
+ array_length_index = reader.get_attribute ("length").to_int ();
+ }
+ next ();
+ var element_type = parse_type ();
+ end_element ("array");
+ return new ArrayType (element_type, 1, null);
+ } else {
+ start_element ("type");
+ DataType type = parse_type_from_name (reader.get_attribute ("name"));
+ next ();
+
+ // type arguments / element types
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ parse_type ();
+ }
+
+ end_element ("type");
+ return type;
+ }
+ }
+
+ DataType parse_type_from_name (string type_name) {
+ DataType type;
+ if (type_name == "none") {
+ type = new VoidType ();
+ } else if (type_name == "any") {
+ type = new PointerType (new VoidType ());
+ } else if (type_name == "GObject.Strv") {
+ type = new ArrayType (new UnresolvedType.from_symbol (new UnresolvedSymbol (null, "string")), 1, null);
+ } else {
+ if (type_name == "utf8") {
+ type_name = "string";
+ } else if (type_name == "boolean") {
+ type_name = "bool";
+ } else if (type_name == "GType") {
+ type_name = "GLib.Type";
+ } else if (type_name == "GObject.String") {
+ type_name = "GLib.StringBuilder";
+ } else if (type_name == "GObject.Class") {
+ type_name = "GLib.ObjectClass";
+ } else if (type_name == "GLib.unichar") {
+ type_name = "unichar";
+ } else if (type_name == "GLib.Data") {
+ type_name = "GLib.Datalist";
+ }
+ string[] type_components = type_name.split (".");
+ if (type_components[1] != null) {
+ // namespaced name
+ string namespace_name = type_components[0];
+ string transformed_type_name = type_components[1];
+ if (namespace_name == "GObject") {
+ namespace_name = "GLib";
+ } else if (namespace_name == "Gio") {
+ namespace_name = "GLib";
+ }
+ type = new UnresolvedType.from_symbol (new UnresolvedSymbol (new UnresolvedSymbol (null, namespace_name), transformed_type_name));
+ } else {
+ type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_name));
+ }
+ }
+
+ return type;
+ }
+
+ Struct parse_record () {
+ start_element ("record");
+ var st = new Struct (reader.get_attribute ("name"));
+ st.access = SymbolAccessibility.PUBLIC;
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ if (reader.name == "field") {
+ st.add_field (parse_field ());
+ } else if (reader.name == "callback") {
+ parse_callback ();
+ } else if (reader.name == "constructor") {
+ parse_constructor ();
+ } else if (reader.name == "method") {
+ parse_method ();
+ } else {
+ // error
+ Report.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader.name));
+ break;
+ }
+ }
+ end_element ("record");
+ return st;
+ }
+
+ Class parse_class () {
+ start_element ("class");
+ var cl = new Class (reader.get_attribute ("name"));
+ cl.access = SymbolAccessibility.PUBLIC;
+
+ string parent = reader.get_attribute ("parent");
+ if (parent != null) {
+ cl.add_base_type (parse_type_from_name (parent));
+ }
+
+ next ();
+ var signals = new ArrayList<Signal> ();
+ var methods = new ArrayList<Method> ();
+ var fields = new ArrayList<Field> ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ if (reader.name == "implements") {
+ start_element ("implements");
+ cl.add_base_type (parse_type_from_name (reader.get_attribute ("name")));
+ next ();
+ end_element ("implements");
+ } else if (reader.name == "field") {
+ fields.add (parse_field ());
+ } else if (reader.name == "property") {
+ cl.add_property (parse_property ());
+ } else if (reader.name == "constructor") {
+ cl.add_method (parse_constructor ());
+ } else if (reader.name == "method") {
+ methods.add (parse_method ());
+ } else if (reader.name == "callback") {
+ parse_callback ();
+ } else if (reader.name == "glib:signal") {
+ signals.add (parse_signal ());
+ } else {
+ // error
+ Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
+ break;
+ }
+ }
+
+ // signal merging
+ foreach (Signal sig in signals) {
+ var symbol = cl.scope.lookup (sig.name);
+ if (symbol == null) {
+ cl.add_signal (sig);
+ } else if (symbol is Property) {
+ // properties take precedence
+ } else {
+ Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (sig.name, cl.name));
+ }
+ }
+
+ // method merging
+ foreach (Method m in methods) {
+ var symbol = cl.scope.lookup (m.name);
+ if (symbol == null) {
+ cl.add_method (m);
+ } else if (symbol is Signal) {
+ var sig = (Signal) symbol;
+ sig.has_emitter = true;
+ } else if (symbol is Property || symbol is Field) {
+ // assume method is getter for property/field ignore method
+ } else {
+ Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, cl.name));
+ }
+ }
+
+ // fields have lowest priority
+ foreach (Field f in fields) {
+ var symbol = cl.scope.lookup (f.name);
+ if (symbol == null) {
+ cl.add_field (f);
+ }
+ }
+
+ end_element ("class");
+ return cl;
+ }
+
+ Interface parse_interface () {
+ start_element ("interface");
+ var iface = new Interface (reader.get_attribute ("name"));
+ iface.access = SymbolAccessibility.PUBLIC;
+ next ();
+ var methods = new ArrayList<Method> ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ if (reader.name == "field") {
+ parse_field ();
+ } else if (reader.name == "property") {
+ iface.add_property (parse_property ());
+ } else if (reader.name == "callback") {
+ parse_callback ();
+ } else if (reader.name == "method") {
+ methods.add (parse_method ());
+ } else if (reader.name == "glib:signal") {
+ iface.add_signal (parse_signal ());
+ } else {
+ // error
+ Report.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader.name));
+ break;
+ }
+ }
+
+ // method merging
+ foreach (Method m in methods) {
+ var symbol = iface.scope.lookup (m.name);
+ if (symbol == null) {
+ iface.add_method (m);
+ } else if (symbol is Signal) {
+ var sig = (Signal) symbol;
+ sig.has_emitter = true;
+ } else {
+ Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, iface.name));
+ }
+ }
+
+ end_element ("interface");
+ return iface;
+ }
+
+ Field parse_field () {
+ start_element ("field");
+ string name = reader.get_attribute ("name");
+ next ();
+ var type = parse_type ();
+ var field = new Field (name, type, null);
+ field.access = SymbolAccessibility.PUBLIC;
+ end_element ("field");
+ return field;
+ }
+
+ Property parse_property () {
+ start_element ("property");
+ string name = string.joinv ("_", reader.get_attribute ("name").split ("-"));
+ next ();
+ var type = parse_type ();
+ var prop = new Property (name, type, null, null);
+ prop.access = SymbolAccessibility.PUBLIC;
+ prop.get_accessor = new PropertyAccessor (true, false, false, null, null);
+ prop.set_accessor = new PropertyAccessor (false, true, false, null, null);
+ end_element ("property");
+ return prop;
+ }
+
+ Delegate parse_callback () {
+ start_element ("callback");
+ string name = reader.get_attribute ("name");
+ next ();
+ DataType return_type;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
+ return_type = parse_return_value ();
+ } else {
+ return_type = new VoidType ();
+ }
+ var d = new Delegate (name, return_type);
+ d.access = SymbolAccessibility.PUBLIC;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+ start_element ("parameters");
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ d.add_parameter (parse_parameter ());
+ }
+ end_element ("parameters");
+ }
+ end_element ("callback");
+ return d;
+ }
+
+ Method parse_constructor () {
+ start_element ("constructor");
+ string name = reader.get_attribute ("name");
+ next ();
+
+ var return_type = parse_return_value ();
+
+ var m = new CreationMethod (null, name);
+ m.access = SymbolAccessibility.PUBLIC;
+ m.has_construct_function = false;
+ if (m.name.has_prefix ("new_")) {
+ m.name = m.name.offset ("new_".len ());
+ }
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+ start_element ("parameters");
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ m.add_parameter (parse_parameter ());
+ }
+ end_element ("parameters");
+ }
+ end_element ("constructor");
+ return m;
+ }
+
+ Method parse_method () {
+ start_element ("method");
+ string name = reader.get_attribute ("name");
+ next ();
+ DataType return_type;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
+ return_type = parse_return_value ();
+ } else {
+ return_type = new VoidType ();
+ }
+ var m = new Method (name, return_type);
+ m.access = SymbolAccessibility.PUBLIC;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+ start_element ("parameters");
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ m.add_parameter (parse_parameter ());
+ }
+ end_element ("parameters");
+ }
+ end_element ("method");
+ return m;
+ }
+
+ Signal parse_signal () {
+ start_element ("glib:signal");
+ string name = string.joinv ("_", reader.get_attribute ("name").split ("-"));
+ next ();
+ DataType return_type;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
+ return_type = parse_return_value ();
+ } else {
+ return_type = new VoidType ();
+ }
+ var sig = new Signal (name, return_type);
+ sig.access = SymbolAccessibility.PUBLIC;
+ sig.is_virtual = true;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+ start_element ("parameters");
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ sig.add_parameter (parse_parameter ());
+ }
+ end_element ("parameters");
+ }
+ end_element ("glib:signal");
+ return sig;
+ }
+
+ Struct parse_boxed () {
+ start_element ("glib:boxed");
+ var st = new Struct (reader.get_attribute ("glib:name"));
+ st.access = SymbolAccessibility.PUBLIC;
+ next ();
+
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ if (reader.name == "field") {
+ st.add_field (parse_field ());
+ } else if (reader.name == "constructor") {
+ parse_constructor ();
+ } else if (reader.name == "method") {
+ st.add_method (parse_method ());
+ } else {
+ // error
+ Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
+ break;
+ }
+ }
+
+ end_element ("glib:boxed");
+ return st;
+ }
+
+ Struct parse_union () {
+ start_element ("union");
+ var st = new Struct (reader.get_attribute ("name"));
+ st.access = SymbolAccessibility.PUBLIC;
+ next ();
+
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+ if (reader.name == "field") {
+ st.add_field (parse_field ());
+ } else if (reader.name == "constructor") {
+ parse_constructor ();
+ } else if (reader.name == "method") {
+ st.add_method (parse_method ());
+ } else {
+ // error
+ Report.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader.name));
+ break;
+ }
+ }
+
+ end_element ("union");
+ return st;
+ }
+
+ Constant parse_constant () {
+ start_element ("constant");
+ string name = reader.get_attribute ("name");
+ next ();
+ var type = parse_type ();
+ var c = new Constant (name, type, null, null);
+ c.access = SymbolAccessibility.PUBLIC;
+ end_element ("constant");
+ return c;
+ }
+
+ public void parse_metadata (string metadata_filename) {
+ if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
+ try {
+ string metadata;
+ ulong metadata_len;
+ FileUtils.get_contents (metadata_filename, out metadata, out metadata_len);
+
+ foreach (string line in metadata.split ("\n")) {
+ if (line.has_prefix ("#")) {
+ // ignore comment lines
+ continue;
+ }
+
+ string[] tokens = line.split (" ", 2);
+
+ if (null == tokens[0]) {
+ continue;
+ }
+
+ foreach (string attribute in tokens[1].split (" ")) {
+ string[] pair = attribute.split ("=", 2);
+ string key = "%s/@%s".printf (tokens[0], pair[0]);
+ attributes_map.set (key, pair[1].substring (1, pair[1].length - 2));
+ }
+ }
+ } catch (FileError e) {
+ Report.error (null, "Unable to read metadata file: %s".printf (e.message));
+ }
+ } else {
+ Report.error (null, "Metadata file `%s' not found".printf (metadata_filename));
+ }
+ }
+
+ string? get_attribute (string node, string key) {
+ return attributes_map["%s/@%s".printf (node, key)];
+ }
+}
+
Added: trunk/vapigen/valamarkupreader.vala
==============================================================================
--- (empty file)
+++ trunk/vapigen/valamarkupreader.vala Fri Oct 17 13:41:33 2008
@@ -0,0 +1,233 @@
+/* valamarkupreader.vala
+ *
+ * Copyright (C) 2008 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:
+ * JÃrg Billeter <j bitron ch>
+ */
+
+using GLib;
+using Gee;
+
+/**
+ * Simple reader for a subset of XML.
+ */
+public class Vala.MarkupReader : Object {
+ public string filename { get; construct; }
+
+ public string name { get; private set; }
+
+ MappedFile mapped_file;
+
+ char* begin;
+ char* current;
+ char* end;
+
+ int line;
+ int column;
+
+ Map<string,string> attributes = new HashMap<string,string> (str_hash, str_equal);
+ bool empty_element;
+
+ public MarkupReader (string filename) {
+ this.filename = filename;
+ }
+
+ construct {
+ try {
+ mapped_file = new MappedFile (filename, false);
+ begin = mapped_file.get_contents ();
+ end = begin + mapped_file.get_length ();
+
+ current = begin;
+
+ line = 1;
+ column = 1;
+ } catch (FileError e) {
+ Report.error (null, "Unable to map file `%s': %s".printf (filename, e.message));
+ }
+ }
+
+ public string? get_attribute (string attr) {
+ return attributes[attr];
+ }
+
+ string read_name () {
+ char* begin = current;
+ while (current < end) {
+ if (current[0] == ' ' || current[0] == '>'
+ || current[0] == '/' || current[0] == '=') {
+ break;
+ }
+ unichar u = ((string) current).get_char_validated ((long) (end - current));
+ if (u != (unichar) (-1)) {
+ current += u.to_utf8 (null);
+ } else {
+ Report.error (null, "invalid UTF-8 character");
+ }
+ }
+ if (current == begin) {
+ // syntax error: invalid name
+ }
+ return ((string) begin).ndup (current - begin);
+ }
+
+ public MarkupTokenType read_token (out SourceLocation token_begin, out SourceLocation token_end) {
+ attributes.clear ();
+
+ if (empty_element) {
+ empty_element = false;
+ return MarkupTokenType.END_ELEMENT;
+ }
+
+ space ();
+
+ MarkupTokenType type;
+ char* begin = current;
+ token_begin.pos = begin;
+ token_begin.line = line;
+ token_begin.column = column;
+
+ if (current >= end) {
+ type = MarkupTokenType.EOF;
+ } else if (current[0] == '<') {
+ current++;
+ if (current >= end) {
+ // error
+ } else if (current[0] == '?') {
+ // processing instruction
+ } else if (current[0] == '!') {
+ // comment or doctype
+ } else if (current[0] == '/') {
+ type = MarkupTokenType.END_ELEMENT;
+ current++;
+ name = read_name ();
+ if (current >= end || current[0] != '>') {
+ // error
+ }
+ current++;
+ } else {
+ type = MarkupTokenType.START_ELEMENT;
+ name = read_name ();
+ space ();
+ while (current < end && current[0] != '>' && current[0] != '/') {
+ string attr_name = read_name ();
+ if (current >= end || current[0] != '=') {
+ // error
+ }
+ current++;
+ // FIXME allow single quotes
+ if (current >= end || current[0] != '"') {
+ // error
+ }
+ current++;
+ char* attr_begin = current;
+ while (current < end && current[0] != '"') {
+ if (current[0] == '&') {
+ // process & > < " '
+ } else {
+ unichar u = ((string) current).get_char_validated ((long) (end - current));
+ if (u != (unichar) (-1)) {
+ current += u.to_utf8 (null);
+ } else {
+ Report.error (null, "invalid UTF-8 character");
+ }
+ }
+ }
+ string attr_value = ((string) attr_begin).ndup (current - attr_begin);
+ if (current >= end || current[0] != '"') {
+ // error
+ }
+ current++;
+ attributes.set (attr_name, attr_value);
+ space ();
+ }
+ if (current[0] == '/') {
+ empty_element = true;
+ current++;
+ space ();
+ } else {
+ empty_element = false;
+ }
+ if (current >= end || current[0] != '>') {
+ // error
+ }
+ current++;
+ }
+ } else {
+ space ();
+ char* text_begin = current;
+ while (current < end && current[0] != '<') {
+ if (current[0] == '&') {
+ // process & > < " '
+ } else {
+ unichar u = ((string) current).get_char_validated ((long) (end - current));
+ if (u != (unichar) (-1)) {
+ current += u.to_utf8 (null);
+ } else {
+ Report.error (null, "invalid UTF-8 character");
+ }
+ }
+ }
+ if (text_begin == current) {
+ // no text
+ // read next token
+ return read_token (out token_begin, out token_end);
+ }
+ type = MarkupTokenType.TEXT;
+ string text = ((string) text_begin).ndup (current - text_begin);
+ }
+
+ column += (int) (current - begin);
+
+ token_end.pos = current;
+ token_end.line = line;
+ token_end.column = column - 1;
+
+ return type;
+ }
+
+ void space () {
+ while (current < end && current[0].isspace ()) {
+ if (current[0] == '\n') {
+ line++;
+ column = 0;
+ }
+ current++;
+ column++;
+ }
+ }
+}
+
+public enum Vala.MarkupTokenType {
+ NONE,
+ START_ELEMENT,
+ END_ELEMENT,
+ TEXT,
+ EOF;
+
+ public weak string to_string () {
+ switch (this) {
+ case START_ELEMENT: return "start element";
+ case END_ELEMENT: return "end element";
+ case TEXT: return "text";
+ case EOF: return "end of file";
+ default: return "unknown token type";
+ }
+ }
+}
+
Modified: trunk/vapigen/valavapigen.vala
==============================================================================
--- trunk/vapigen/valavapigen.vala (original)
+++ trunk/vapigen/valavapigen.vala Fri Oct 17 13:41:33 2008
@@ -33,12 +33,14 @@
static string library;
[NoArrayLength ()]
static string[] packages;
+ static string metadata_filename;
CodeContext context;
const OptionEntry[] options = {
{ "vapidir", 0, 0, OptionArg.FILENAME_ARRAY, ref vapi_directories, "Look for package bindings in DIRECTORY", "DIRECTORY..." },
{ "pkg", 0, 0, OptionArg.STRING_ARRAY, ref packages, "Include binding for PACKAGE", "PACKAGE..." },
{ "library", 0, 0, OptionArg.STRING, ref library, "Library name", "NAME" },
+ { "metadata", 0, 0, OptionArg.FILENAME, ref metadata_filename, "Metadata filename", "FILE" },
{ "directory", 'd', 0, OptionArg.FILENAME, ref directory, "Output directory", "DIRECTORY" },
{ "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 },
@@ -157,6 +159,16 @@
return quit ();
}
+ var girparser = new GirParser ();
+ if (metadata_filename != null) {
+ girparser.parse_metadata (metadata_filename);
+ }
+ girparser.parse (context);
+
+ if (Report.get_errors () > 0) {
+ return quit ();
+ }
+
var gidlparser = new GIdlParser ();
gidlparser.parse (context);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]