/* valagirwriter.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 */ using GLib; using Gee; /** * Code visitor generating .gir file for the public interface. */ public class Vala.GIRWriter : CodeVisitor { private CodeContext context; FileStream stream; int indent; private TypeSymbol gobject_type; /** * Writes the public interface of the specified code context into the * specified file. * * @param context a code context * @param filename a relative or absolute filename */ public void write_file (CodeContext context, string filename) { this.context = context; var root_symbol = context.root; var glib_ns = root_symbol.scope.lookup ("GLib"); gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object"); stream = FileStream.open (filename, "w"); stream.printf ("\n"); stream.printf ("\n"); context.accept (this); stream.printf ("\n"); stream = null; } public override void visit_namespace (Namespace ns) { if (ns.external_package) { return; } if (ns.name == null) { // global namespace ns.accept_children (this); return; } if (ns.parent_symbol.name != null) { // nested namespace // not supported in GIR at the moment return; } write_indent (); stream.printf ("\n", ns.name); indent++; ns.accept_children (this); indent--; write_indent (); stream.printf ("\n"); } public override void visit_class (Class cl) { if (cl.external_package) { return; } if (!check_accessibility (cl)) { return; } if (cl.is_subtype_of (gobject_type)) { write_indent (); stream.printf ("\n"); indent++; // write implemented interfaces bool first = true; foreach (DataType base_type in cl.get_base_types ()) { var object_type = (ObjectType) base_type; if (object_type.type_symbol is Interface) { if (first) { write_indent (); stream.printf ("\n"); indent++; first = false; } write_indent (); stream.printf ("\n", object_type.type_symbol.get_full_name ()); } } if (!first) { indent--; write_indent (); stream.printf ("\n"); } cl.accept_children (this); indent--; write_indent (); stream.printf ("\n"); } else { write_indent (); stream.printf ("\n"); indent++; cl.accept_children (this); indent--; write_indent (); stream.printf ("\n"); } } public override void visit_struct (Struct st) { if (st.external_package) { return; } if (!check_accessibility (st)) { return; } write_indent (); stream.printf ("\n"); indent++; st.accept_children (this); indent--; write_indent (); stream.printf ("\n"); } public override void visit_interface (Interface iface) { if (iface.external_package) { return; } if (!check_accessibility (iface)) { return; } write_indent (); stream.printf ("\n"); indent++; // write prerequisites if (iface.get_prerequisites ().size > 0) { write_indent (); stream.printf ("\n"); indent++; foreach (DataType base_type in iface.get_prerequisites ()) { var object_type = (ObjectType) base_type; if (object_type.type_symbol is Class) { write_indent (); stream.printf ("\n", object_type.type_symbol.get_full_name ()); } else if (object_type.type_symbol is Interface) { write_indent (); stream.printf ("\n", object_type.type_symbol.get_full_name ()); } else { assert_not_reached (); } } indent--; write_indent (); stream.printf ("\n"); } iface.accept_children (this); indent--; write_indent (); stream.printf ("\n"); } public override void visit_enum (Enum en) { if (en.external_package) { return; } if (!check_accessibility (en)) { return; } write_indent (); stream.printf ("\n"); indent++; en.accept_children (this); indent--; write_indent (); stream.printf ("\n"); } public override void visit_enum_value (EnumValue ev) { write_indent (); stream.printf ("\n", string.joinv ("-", ev.name.down ().split ("_"))); } public override void visit_error_domain (ErrorDomain edomain) { if (edomain.external_package) { return; } if (!check_accessibility (edomain)) { return; } write_indent (); stream.printf ("\n"); indent++; edomain.accept_children (this); indent--; write_indent (); stream.printf ("\n"); } public override void visit_error_code (ErrorCode ecode) { write_indent (); stream.printf ("\n", ecode.get_cname ()); } public override void visit_constant (Constant c) { if (c.external_package) { return; } if (!check_accessibility (c)) { return; } write_indent (); stream.printf ("\n", c.get_cname ()); } public override void visit_field (Field f) { if (f.external_package) { return; } if (!check_accessibility (f)) { return; } write_indent (); stream.printf ("\n", f.get_cname ()); indent++; write_type (f.field_type); indent--; write_indent (); stream.printf ("\n"); } private void write_params (Gee.List params, DataType? instance_type = null) { write_indent (); stream.printf ("\n"); indent++; if (instance_type != null) { write_indent (); stream.printf ("\n"); indent++; write_type (instance_type); indent--; write_indent (); stream.printf ("\n"); } foreach (FormalParameter param in params) { write_indent (); stream.printf ("\n"); indent++; write_type (param.parameter_type); indent--; write_indent (); stream.printf ("\n"); } indent--; write_indent (); stream.printf ("\n"); } public override void visit_delegate (Delegate cb) { if (cb.external_package) { return; } if (!check_accessibility (cb)) { return; } write_indent (); stream.printf ("\n"); indent++; write_params (cb.get_parameters ()); write_return_type (cb.return_type); indent--; write_indent (); stream.printf ("\n"); } public override void visit_method (Method m) { if (m.external_package) { return; } // don't write interface implementation unless it's an abstract or virtual method if (!check_accessibility (m) || m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) { return; } write_indent (); stream.printf ("\n"); indent++; DataType instance_type = null; if (m.binding == MemberBinding.INSTANCE) { instance_type = CCodeGenerator.get_data_type_for_symbol ((TypeSymbol) m.parent_symbol); } write_params (m.get_parameters (), instance_type); write_return_type (m.return_type); indent--; write_indent (); stream.printf ("\n"); } public override void visit_creation_method (CreationMethod m) { if (m.external_package) { return; } if (!check_accessibility (m)) { return; } write_indent (); stream.printf ("\n"); indent++; write_params (m.get_parameters ()); write_return_type (CCodeGenerator.get_data_type_for_symbol ((TypeSymbol) m.parent_symbol)); indent--; write_indent (); stream.printf ("\n"); } public override void visit_property (Property prop) { if (!check_accessibility (prop) || prop.overrides || (prop.base_interface_property != null && !prop.is_abstract && !prop.is_virtual)) { return; } write_indent (); stream.printf ("\n"); indent++; write_type (prop.property_type); indent--; write_indent (); stream.printf ("\n"); } public override void visit_signal (Signal sig) { if (!check_accessibility (sig)) { return; } write_indent (); stream.printf ("\n"); indent++; write_params (sig.get_parameters ()); write_return_type (sig.return_type); indent--; write_indent (); stream.printf ("\n"); } private void write_indent () { int i; for (i = 0; i < indent; i++) { stream.putc ('\t'); } } private void write_return_type (DataType type) { write_indent (); stream.printf ("\n"); indent++; write_type (type); indent--; write_indent (); stream.printf ("\n"); } private void write_type (DataType type) { if (type is ArrayType) { var array_type = (ArrayType) type; write_indent (); stream.printf ("\n"); indent++; write_type (array_type.element_type); indent--; write_indent (); stream.printf ("\n"); } else if (type is VoidType) { write_indent (); stream.printf ("\n"); } else { write_indent (); stream.printf ("\n", type.to_string ()); } } private bool check_accessibility (Symbol sym) { if (sym.access == SymbolAccessibility.PUBLIC || sym.access == SymbolAccessibility.PROTECTED) { return true; } return false; } }