support creating GTypeModule-based plug-ins with the ModuleInit attribute
authorJürg Billeter <j@bitron.ch>
Sat, 17 Mar 2007 14:29:00 +0000 (14:29 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sat, 17 Mar 2007 14:29:00 +0000 (14:29 +0000)
2007-03-17  Jürg Billeter  <j@bitron.ch>

* vala/valasemanticanalyzer.vala, vala/valacodegnerator.vala,
  vala/valaclassregisterfunction.vala,
  vala/valainterfaceregisterfunction.vala,
  vala/valatyperegisterfunction.vala, vala/valacodecontext.vala: support
  creating GTypeModule-based plug-ins with the ModuleInit attribute
* vala/parser.y, vala/valacodegenerator.vala, vala/valaclass.vala:
  support static classes
* vapi/glib-2.0.vala: add TypePlugin and TypeModule

svn path=/trunk/; revision=242

vala/ChangeLog
vala/vala/parser.y
vala/vala/valaclass.vala
vala/vala/valaclassregisterfunction.vala
vala/vala/valacodecontext.vala
vala/vala/valacodegenerator.vala
vala/vala/valainterfaceregisterfunction.vala
vala/vala/valasemanticanalyzer.vala
vala/vala/valatyperegisterfunction.vala
vala/vapi/glib-2.0.vala

index ab7073b..05cbd49 100644 (file)
@@ -1,5 +1,16 @@
 2007-03-17  Jürg Billeter  <j@bitron.ch>
 
+       * vala/valasemanticanalyzer.vala, vala/valacodegnerator.vala,
+         vala/valaclassregisterfunction.vala,
+         vala/valainterfaceregisterfunction.vala,
+         vala/valatyperegisterfunction.vala, vala/valacodecontext.vala: support
+         creating GTypeModule-based plug-ins with the ModuleInit attribute
+       * vala/parser.y, vala/valacodegenerator.vala, vala/valaclass.vala:
+         support static classes
+       * vapi/glib-2.0.vala: add TypePlugin and TypeModule
+
+2007-03-17  Jürg Billeter  <j@bitron.ch>
+
        * vala/parser.y: accept attributes without parentheses
        * vala/valainterfacewriter.vala: don't write weak keyword for value
          types
index af87d5a..c4dca5d 100644 (file)
@@ -2210,6 +2210,9 @@ class_declaration
                if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) {
                        vala_class_set_is_abstract (current_class, TRUE);
                }
+               if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
+                       vala_class_set_is_static (current_class, TRUE);
+               }
                if ($8 != NULL) {
                        for (l = $8; l != NULL; l = l->next) {
                                vala_class_add_type_parameter (current_class, l->data);
index ca4a433..aacf05e 100644 (file)
@@ -36,7 +36,13 @@ public class Vala.Class : DataType {
         * instantiated.
         */
        public bool is_abstract { get; set; }
-       
+
+       /**
+        * Specifies whether this class is static. Static classes may not be
+        * instantiated and may only contain static members.
+        */
+       public bool is_static { get; set; }
+
        /**
         * Specifies whether this class has private fields.
         */
index c6fc43a..607a049 100644 (file)
@@ -94,7 +94,7 @@ public class Vala.ClassRegisterFunction : TypeRegisterFunction {
                        ctypedecl.add_declarator (new CCodeVariableDeclarator.with_initializer (iface_info_name, new CCodeConstant ("{ (GInterfaceInitFunc) %s_%s_interface_init, (GInterfaceFinalizeFunc) NULL, NULL}".printf (class_reference.get_lower_case_cname (null), iface.get_lower_case_cname (null)))));
                        frag.append (ctypedecl);
                        var reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_add_interface_static"));
-                       reg_call.add_argument (new CCodeIdentifier ("g_define_type_id"));
+                       reg_call.add_argument (new CCodeIdentifier ("%s_type_id".printf (class_reference.get_lower_case_cname (null))));
                        reg_call.add_argument (new CCodeIdentifier (iface.get_upper_case_cname ("TYPE_")));
                        reg_call.add_argument (new CCodeIdentifier ("&%s".printf (iface_info_name)));
                        frag.append (new CCodeExpressionStatement (reg_call));
index 374cd8e..40d64d8 100644 (file)
@@ -1,6 +1,6 @@
 /* valacodecontext.vala
  *
- * Copyright (C) 2006  Jürg Billeter
+ * Copyright (C) 2006-2007  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
@@ -34,6 +34,11 @@ public class Vala.CodeContext {
         */
        public string library { get; set; }
 
+       /**
+        * Specifies the optional module initialization method.
+        */
+       public Method module_init_method { get; set; }
+
        List<SourceFile> source_files;
        private Symbol! root = new Symbol ();
        
index ad6be31..3908e06 100644 (file)
@@ -52,6 +52,7 @@ public class Vala.CodeGenerator : CodeVisitor {
        CCodeFragment instance_init_fragment;
        CCodeFragment instance_dispose_fragment;
        CCodeFragment source_signal_marshaller_definition;
+       CCodeFragment module_init_fragment;
        
        CCodeStruct instance_struct;
        CCodeStruct type_struct;
@@ -89,7 +90,11 @@ public class Vala.CodeGenerator : CodeVisitor {
        DataType list_type;
        DataType slist_type;
        TypeReference mutex_type;
-       
+       DataType type_module_type;
+
+       private bool in_plugin = false;
+       private string module_init_param_name;
+
        public CodeGenerator (bool manage_memory = true) {
                memory_management = manage_memory;
        }
@@ -177,6 +182,19 @@ public class Vala.CodeGenerator : CodeVisitor {
                
                mutex_type = new TypeReference ();
                mutex_type.data_type = (DataType) glib_ns.lookup ("Mutex").node;
+               
+               type_module_type = (DataType) glib_ns.lookup ("TypeModule").node;
+
+               if (context.module_init_method != null) {
+                       module_init_fragment = new CCodeFragment ();
+                       foreach (FormalParameter parameter in context.module_init_method.get_parameters ()) {
+                               if (parameter.type_reference.data_type == type_module_type) {
+                                       in_plugin = true;
+                                       module_init_param_name = parameter.name;
+                                       break;
+                               }
+                       }
+               }
        
                /* we're only interested in non-pkg source files */
                var source_files = context.get_source_files ();
@@ -354,6 +372,10 @@ public class Vala.CodeGenerator : CodeVisitor {
                current_type_symbol = cl.symbol;
                current_class = cl;
 
+               if (cl.is_static) {
+                       return;
+               }
+
                instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ()));
                type_struct = new CCodeStruct ("_%sClass".printf (cl.get_cname ()));
                instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (cl.get_cname ()));
@@ -406,25 +428,34 @@ public class Vala.CodeGenerator : CodeVisitor {
        }
        
        public override void visit_end_class (Class! cl) {
-               add_get_property_function (cl);
-               add_set_property_function (cl);
-               add_class_init_function (cl);
-               
-               foreach (TypeReference base_type in cl.get_base_types ()) {
-                       if (base_type.data_type is Interface) {
-                               add_interface_init_function (cl, (Interface) base_type.data_type);
+               if (!cl.is_static) {
+                       add_get_property_function (cl);
+                       add_set_property_function (cl);
+                       add_class_init_function (cl);
+                       
+                       foreach (TypeReference base_type in cl.get_base_types ()) {
+                               if (base_type.data_type is Interface) {
+                                       add_interface_init_function (cl, (Interface) base_type.data_type);
+                               }
+                       }
+                       
+                       add_instance_init_function (cl);
+                       if (memory_management && cl.get_fields () != null) {
+                               add_dispose_function (cl);
+                       }
+                       
+                       var type_fun = new ClassRegisterFunction (cl);
+                       type_fun.init_from_type (in_plugin);
+                       header_type_member_declaration.append (type_fun.get_declaration ());
+                       source_type_member_definition.append (type_fun.get_definition ());
+                       
+                       if (in_plugin) {
+                               // FIXME resolve potential dependency issues, i.e. base types have to be registered before derived types
+                               var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (cl.get_lower_case_cname (null))));
+                               register_call.add_argument (new CCodeIdentifier (module_init_param_name));
+                               module_init_fragment.append (new CCodeExpressionStatement (register_call));
                        }
                }
-               
-               add_instance_init_function (cl);
-               if (memory_management && cl.get_fields () != null) {
-                       add_dispose_function (cl);
-               }
-               
-               var type_fun = new ClassRegisterFunction (cl);
-               type_fun.init_from_type ();
-               header_type_member_declaration.append (type_fun.get_declaration ());
-               source_type_member_definition.append (type_fun);
 
                current_type_symbol = null;
                current_class = null;
@@ -841,7 +872,7 @@ public class Vala.CodeGenerator : CodeVisitor {
                var type_fun = new InterfaceRegisterFunction (iface);
                type_fun.init_from_type ();
                header_type_member_declaration.append (type_fun.get_declaration ());
-               source_type_member_definition.append (type_fun);
+               source_type_member_definition.append (type_fun.get_definition ());
 
                current_type_symbol = null;
        }
@@ -1356,6 +1387,11 @@ public class Vala.CodeGenerator : CodeVisitor {
                                        cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params_it", new CCodeIdentifier ("__params")));
                                        cinit.append (cdecl);
                                }
+
+                               if (context.module_init_method == m && in_plugin) {
+                                       // GTypeModule-based plug-in, register types
+                                       cinit.append (module_init_fragment);
+                               }
                        }
                }
                
index cda7b6b..7b9a94d 100644 (file)
@@ -72,7 +72,7 @@ public class Vala.InterfaceRegisterFunction : TypeRegisterFunction {
                        var prereq = prereq_ref.data_type;
                        
                        var func = new CCodeFunctionCall (new CCodeIdentifier ("g_type_interface_add_prerequisite"));
-                       func.add_argument (new CCodeIdentifier ("g_define_type_id"));
+                       func.add_argument (new CCodeIdentifier ("%s_type_id".printf (interface_reference.get_lower_case_cname (null))));
                        func.add_argument (new CCodeIdentifier (prereq.get_type_id()));
                        
                        frag.append (new CCodeExpressionStatement (func));
index de18e12..766802c 100644 (file)
@@ -303,7 +303,12 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        public override void visit_begin_method (Method! m) {   
                current_symbol = m.symbol;
                current_return_type = m.return_type;
-               
+
+               var init_attr = m.get_attribute ("ModuleInit");
+               if (init_attr != null) {
+                       m.source_reference.file.context.module_init_method = m;
+               }
+
                if (m.return_type.data_type != null) {
                        /* is null if it is void or a reference to a type parameter */
                        current_source_file.add_symbol_dependency (m.return_type.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
index 95501c6..d8a3044 100644 (file)
@@ -25,41 +25,80 @@ using GLib;
 /**
  * C function to register a type at runtime.
  */
-public abstract class Vala.TypeRegisterFunction : CCodeFunction {
+public abstract class Vala.TypeRegisterFunction {
+       private CCodeFragment declaration_fragment = new CCodeFragment ();
+
+       private CCodeFragment definition_fragment = new CCodeFragment ();
+
        /**
         * Constructs the C function from the specified type.
         */
-       public void init_from_type () {
-               name = "%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null));
-               return_type = "GType";
+       public void init_from_type (bool plugin = false) {
+               string type_id_name = "%s_type_id".printf (get_type_declaration ().get_lower_case_cname (null));
 
                var type_block = new CCodeBlock ();
                var cdecl = new CCodeDeclaration ("GType");
-               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("g_define_type_id", new CCodeConstant ("0")));
+               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (type_id_name, new CCodeConstant ("0")));
                cdecl.modifiers = CCodeModifiers.STATIC;
-               type_block.add_statement (cdecl);
-               
-               var cond = new CCodeFunctionCall (new CCodeIdentifier ("G_UNLIKELY"));
-               cond.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("g_define_type_id"), new CCodeConstant ("0")));
+               if (!plugin) {
+                       type_block.add_statement (cdecl);
+               } else {
+                       definition_fragment.append (cdecl);
+               }
+
+               CCodeFunction fun;
+               if (!plugin) {
+                       fun = new CCodeFunction ("%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
+               } else {
+                       fun = new CCodeFunction ("%s_register_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
+                       fun.add_parameter (new CCodeFormalParameter ("module", "GTypeModule *"));
+
+                       var get_fun = new CCodeFunction ("%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
+
+                       declaration_fragment.append (get_fun.copy ());
+
+                       get_fun.block = new CCodeBlock ();
+                       get_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
+
+                       definition_fragment.append (get_fun);
+               }
+
                var type_init = new CCodeBlock ();
                var ctypedecl = new CCodeDeclaration ("const GTypeInfo");
                ctypedecl.modifiers = CCodeModifiers.STATIC;
                ctypedecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("g_define_type_info", new CCodeConstant ("{ sizeof (%s), (GBaseInitFunc) %s, (GBaseFinalizeFunc) NULL, (GClassInitFunc) %s, (GClassFinalizeFunc) NULL, NULL, %s, 0, (GInstanceInitFunc) %s }".printf (get_type_struct_name (), get_base_init_func_name (), get_class_init_func_name (), get_instance_struct_size (), get_instance_init_func_name ()))));
                type_init.add_statement (ctypedecl);
-               var reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_static"));
+               CCodeFunctionCall reg_call;
+               if (!plugin) {
+                       reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_static"));
+               } else {
+                       reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_module_register_type"));
+                       reg_call.add_argument (new CCodeIdentifier ("module"));
+               }
                reg_call.add_argument (new CCodeIdentifier (get_parent_type_name ()));
                reg_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_declaration ().get_cname ())));
                reg_call.add_argument (new CCodeIdentifier ("&g_define_type_info"));
                reg_call.add_argument (new CCodeConstant (get_type_flags ()));
-               type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("g_define_type_id"), reg_call)));
+               type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (type_id_name), reg_call)));
                
                type_init.add_statement (get_type_interface_init_statements ());
-               
-               var cif = new CCodeIfStatement (cond, type_init);
-               type_block.add_statement (cif);
-               type_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("g_define_type_id")));
 
-               block = type_block;
+               if (!plugin) {
+                       var cond = new CCodeFunctionCall (new CCodeIdentifier ("G_UNLIKELY"));
+                       cond.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (type_id_name), new CCodeConstant ("0")));
+                       var cif = new CCodeIfStatement (cond, type_init);
+                       type_block.add_statement (cif);
+               } else {
+                       type_block = type_init;
+               }
+
+               type_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
+
+               declaration_fragment.append (fun.copy ());
+
+               fun.block = type_block;
+
+               definition_fragment.append (fun);
        }
        
        /**
@@ -130,9 +169,18 @@ public abstract class Vala.TypeRegisterFunction : CCodeFunction {
        /**
         * Returns the declaration for this type register function in C code.
         *
-        * @return C function declaration
+        * @return C function declaration fragment
+        */
+       public CCodeFragment! get_declaration () {
+               return declaration_fragment;
+       }
+       
+       /**
+        * Returns the definition for this type register function in C code.
+        *
+        * @return C function definition fragment
         */
-       public ref CCodeFunction! get_declaration () {
-               return new CCodeFunction (name, return_type);
+       public CCodeFragment! get_definition () {
+               return definition_fragment;
        }
 }
index 832f0a5..11f6373 100644 (file)
@@ -1,6 +1,6 @@
 /* glib-2.0.vala
  *
- * Copyright (C) 2006  Jürg Billeter, Raffaele Sandrini
+ * Copyright (C) 2006-2007  Jürg Billeter, Raffaele Sandrini
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -251,7 +251,16 @@ namespace GLib {
        public struct TypeClass {
                
        }
-       
+
+       public interface TypePlugin {
+       }
+
+       public class TypeModule : TypePlugin {
+               public bool use ();
+               public void unuse ();
+               public void set_name (string! name);
+       }
+
        [ReferenceType ()]
        public struct ParamSpec {
        }