]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Add experimental support for yield statements and coroutines
authorJürg Billeter <j@bitron.ch>
Sat, 1 Nov 2008 20:34:39 +0000 (20:34 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sat, 1 Nov 2008 20:34:39 +0000 (20:34 +0000)
2008-11-01  Jürg Billeter  <j@bitron.ch>

* vala/valamethod.vala:
* ccode/valaccodeblock.vala:
* gobject/valaccodebasemodule.vala:
* gobject/valaccodegenerator.vala:
* gobject/valaccodeinvocationexpressionmodule.vala:
* gobject/valaccodemethodmodule.vala:
* gobject/valaccodemodule.vala:

Add experimental support for yield statements and coroutines

svn path=/trunk/; revision=1949

ChangeLog
ccode/valaccodeblock.vala
gobject/valaccodebasemodule.vala
gobject/valaccodegenerator.vala
gobject/valaccodeinvocationexpressionmodule.vala
gobject/valaccodemethodmodule.vala
gobject/valaccodemodule.vala
vala/valamethod.vala

index ac0df11181d285d0536df16a2370b449f69b817e..ecc033f74ec949fc17404162cd77cc857b8f62e6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2008-11-01  Jürg Billeter  <j@bitron.ch>
+
+       * vala/valamethod.vala:
+       * ccode/valaccodeblock.vala:
+       * gobject/valaccodebasemodule.vala:
+       * gobject/valaccodegenerator.vala:
+       * gobject/valaccodeinvocationexpressionmodule.vala:
+       * gobject/valaccodemethodmodule.vala:
+       * gobject/valaccodemodule.vala:
+
+       Add experimental support for yield statements and coroutines
+
 2008-11-01  Jürg Billeter  <j@bitron.ch>
 
        * ccode/valaccodecasestatement.vala:
index 7e9919716d7efff9e38428a9b88d70e343bbc8b8..cff8613fe1b764654b396d30ee2dff2388092871 100644 (file)
@@ -59,7 +59,7 @@ public class Vala.CCodeBlock : CCodeStatement {
                        statement.write_declaration (writer);
 
                        // determine last reachable statement
-                       if (statement is CCodeLabel) {
+                       if (statement is CCodeLabel || statement is CCodeCaseStatement) {
                                last_statement = null;
                        } else if (statement is CCodeReturnStatement || statement is CCodeGotoStatement
                        || statement is CCodeContinueStatement || statement is CCodeBreakStatement) {
index 3dd4abaf5ae51448cfe1ef4487cd1f121a962854..83283949b4d56303a536769c9d6a384fd6ef7915 100644 (file)
@@ -241,6 +241,7 @@ public class Vala.CCodeBaseModule : CCodeModule {
                
                codegen.string_h_needed = false;
                codegen.gvaluecollector_h_needed = false;
+               codegen.gio_h_needed = false;
                codegen.dbus_glib_h_needed = false;
                codegen.requires_free_checked = false;
                codegen.requires_array_free = false;
@@ -344,6 +345,10 @@ public class Vala.CCodeBaseModule : CCodeModule {
                        codegen.source_include_directives.append (new CCodeIncludeDirective ("gobject/gvaluecollector.h"));
                }
 
+               if (codegen.gio_h_needed) {
+                       codegen.header_begin.append (new CCodeIncludeDirective ("gio/gio.h"));
+               }
+
                if (codegen.dbus_glib_h_needed) {
                        codegen.source_include_directives.append (new CCodeIncludeDirective ("dbus/dbus-glib.h"));
                }
index 5773e1c0e82cb1c4a926f1287757ad9d6123c018..4523739378c0eeb228c0119524be27d6ad7d20f7 100644 (file)
@@ -88,6 +88,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
        private bool in_constructor = false;
        public bool in_static_or_class_ctor = false;
        public bool current_method_inner_error = false;
+       int next_coroutine_state = 1;
 
        public DataType bool_type;
        public DataType char_type;
@@ -132,6 +133,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
        
        public bool string_h_needed;
        public bool gvaluecollector_h_needed;
+       public bool gio_h_needed;
        public bool requires_free_checked;
        public bool requires_array_free;
        public bool requires_array_move;
@@ -2680,7 +2682,22 @@ public class Vala.CCodeGenerator : CodeGenerator {
 
        public override void visit_yield_statement (YieldStatement stmt) {
                if (stmt.yield_expression == null) {
-                       stmt.ccodenode = new CCodeFragment ();
+                       var cfrag = new CCodeFragment ();
+                       stmt.ccodenode = cfrag;
+
+                       if (current_method.coroutine) {
+                               var idle_call = new CCodeFunctionCall (new CCodeIdentifier ("g_idle_add"));
+                               idle_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (current_method.get_real_cname ()), "GSourceFunc"));
+                               idle_call.add_argument (new CCodeIdentifier ("data"));
+
+                               int state = next_coroutine_state++;
+
+                               cfrag.append (new CCodeExpressionStatement (idle_call));
+                               cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "state"), new CCodeConstant (state.to_string ()))));
+                               cfrag.append (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
+                               cfrag.append (new CCodeCaseStatement (new CCodeConstant (state.to_string ())));
+                       }
+
                        return;
                }
 
index 9c189e1b0b902fb4a7921a0c8da0c0b63cded0f9..42fd0cdd7387a7ffe0ac282076205980e1582e4f 100644 (file)
@@ -348,6 +348,11 @@ public class Vala.CCodeInvocationExpressionModule : CCodeModule {
                        }
                }
 
+               if (m != null && m.coroutine) {
+                       carg_map.set (codegen.get_param_pos (-1), new CCodeConstant ("NULL"));
+                       carg_map.set (codegen.get_param_pos (-0.9), new CCodeConstant ("NULL"));
+               }
+
                if (expr.tree_can_fail) {
                        // method can fail
                        codegen.current_method_inner_error = true;
index 996cd02cfa90f362f6a942de07ccb14c871acdfb..b87fb020c6e7334dcd679e0bbf0e526d56fe2a09 100644 (file)
@@ -36,7 +36,11 @@ public class Vala.CCodeMethodModule : CCodeModule {
                return (method.get_attribute ("NoWrapper") == null);
        }
 
-       public override string? get_custom_creturn_type (Method m) {\r
+       public override string? get_custom_creturn_type (Method m) {
+               if (m.coroutine) {
+                       return "gboolean";
+               }
+\r
                var attr = m.get_attribute ("CCode");\r
                if (attr != null) {\r
                        string type = attr.get_string ("type");\r
@@ -217,7 +221,14 @@ public class Vala.CCodeMethodModule : CCodeModule {
                        cparam_map.set (codegen.get_param_pos (m.cinstance_parameter_position), class_param);
                }
 
-               generate_cparameters (m, creturn_type, in_gtypeinstance_creation_method, cparam_map, codegen.function, vdeclarator);
+               if (!m.coroutine) {
+                       generate_cparameters (m, creturn_type, in_gtypeinstance_creation_method, cparam_map, codegen.function, vdeclarator);
+               } else {
+                       // data struct to hold parameters, local variables, and the return value
+                       cparam_map.set (codegen.get_param_pos (0), new CCodeFormalParameter ("data", Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data*"));
+
+                       generate_cparameters (m, creturn_type, in_gtypeinstance_creation_method, cparam_map, codegen.function, vdeclarator, null, null, 0);
+               }
 
                bool visible = !m.is_internal_symbol ();
 
@@ -244,6 +255,16 @@ public class Vala.CCodeMethodModule : CCodeModule {
                                var cinit = new CCodeFragment ();
                                codegen.function.block.prepend_statement (cinit);
 
+                               if (m.coroutine) {
+                                       var cswitch = new CCodeSwitchStatement (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "state"));
+                                       cswitch.add_statement (new CCodeCaseStatement (new CCodeConstant ("0")));
+                                       cswitch.add_statement (codegen.function.block);
+                                       cswitch.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
+
+                                       codegen.function.block = new CCodeBlock ();
+                                       codegen.function.block.add_statement (cswitch);
+                               }
+
                                if (m.parent_symbol is Class) {
                                        var cl = (Class) m.parent_symbol;
                                        if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
@@ -514,7 +535,96 @@ public class Vala.CCodeMethodModule : CCodeModule {
                        }
                        codegen.source_type_member_definition.append (vfunc);
                }
-               
+
+               if (m.coroutine) {
+                       codegen.gio_h_needed = true;
+
+                       // generate struct to hold parameters, local variables, and the return value
+                       string dataname = Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data";
+                       var datastruct = new CCodeStruct ("_" + dataname);
+
+                       datastruct.add_field ("int", "state");
+                       datastruct.add_field ("GAsyncReadyCallback", "callback");
+                       datastruct.add_field ("gpointer", "user_data");
+
+                       foreach (FormalParameter param in m.get_parameters ()) {
+                               datastruct.add_field (param.parameter_type.get_cname (), param.name);
+                       }
+
+                       if (!(m.return_type is VoidType)) {
+                               datastruct.add_field (m.return_type.get_cname (), "result");
+                       }
+
+                       codegen.source_type_definition.append (datastruct);
+                       codegen.source_type_declaration.append (new CCodeTypeDefinition ("struct _" + dataname, new CCodeVariableDeclarator (dataname)));
+
+                       // generate async function
+                       var asyncfunc = new CCodeFunction (m.get_cname (), "void");
+                       asyncfunc.line = codegen.function.line;
+
+                       cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+                       var asyncblock = new CCodeBlock ();
+
+                       var dataalloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
+                       dataalloc.add_argument (new CCodeIdentifier (dataname));
+
+                       var datadecl = new CCodeDeclaration (dataname + "*");
+                       datadecl.add_declarator (new CCodeVariableDeclarator ("data"));
+                       asyncblock.add_statement (datadecl);
+                       asyncblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data"), dataalloc)));
+
+                       asyncblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "callback"), new CCodeIdentifier ("callback"))));
+                       asyncblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "user_data"), new CCodeIdentifier ("user_data"))));
+
+                       foreach (FormalParameter param in m.get_parameters ()) {
+                               asyncblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), param.name), new CCodeIdentifier (param.name))));
+                       }
+
+                       var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
+                       ccall.add_argument (new CCodeIdentifier ("data"));
+                       asyncblock.add_statement (new CCodeExpressionStatement (ccall));
+
+                       cparam_map.set (codegen.get_param_pos (-1), new CCodeFormalParameter ("callback", "GAsyncReadyCallback"));
+                       cparam_map.set (codegen.get_param_pos (-0.9), new CCodeFormalParameter ("user_data", "gpointer"));
+
+                       generate_cparameters (m, creturn_type, in_gtypeinstance_creation_method, cparam_map, asyncfunc, null, null, null, 1);
+
+                       if (visible) {
+                               codegen.header_type_member_declaration.append (asyncfunc.copy ());
+                       } else {
+                               asyncfunc.modifiers |= CCodeModifiers.STATIC;
+                               codegen.source_type_member_declaration.append (asyncfunc.copy ());
+                       }
+                       
+                       asyncfunc.block = asyncblock;
+
+                       codegen.source_type_member_definition.append (asyncfunc);
+
+                       // generate finish function
+                       var finishfunc = new CCodeFunction (m.get_cname () + "_finish", creturn_type.get_cname ());
+                       finishfunc.line = codegen.function.line;
+
+                       cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+                       var finishblock = new CCodeBlock ();
+
+                       cparam_map.set (codegen.get_param_pos (0.1), new CCodeFormalParameter ("res", "GAsyncResult*"));
+
+                       generate_cparameters (m, creturn_type, in_gtypeinstance_creation_method, cparam_map, finishfunc, null, null, null, 2);
+
+                       if (visible) {
+                               codegen.header_type_member_declaration.append (finishfunc.copy ());
+                       } else {
+                               finishfunc.modifiers |= CCodeModifiers.STATIC;
+                               codegen.source_type_member_declaration.append (finishfunc.copy ());
+                       }
+                       
+                       finishfunc.block = finishblock;
+
+                       codegen.source_type_member_definition.append (finishfunc);
+               }
+
                if (m is CreationMethod) {
                        if (codegen.current_class != null && !codegen.current_class.is_compact) {
                                var vfunc = new CCodeFunction (m.get_cname (), creturn_type.get_cname ());
@@ -618,7 +728,7 @@ public class Vala.CCodeMethodModule : CCodeModule {
                }
        }
 
-       public override void generate_cparameters (Method m, DataType creturn_type, bool in_gtypeinstance_creation_method, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null) {
+       public override void generate_cparameters (Method m, DataType creturn_type, bool in_gtypeinstance_creation_method, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
                if (in_gtypeinstance_creation_method) {
                        // memory management for generic types
                        int type_param_index = 0;
@@ -636,6 +746,18 @@ public class Vala.CCodeMethodModule : CCodeModule {
                }
 
                foreach (FormalParameter param in m.get_parameters ()) {
+                       if (param.direction != ParameterDirection.OUT) {
+                               if ((direction & 1) == 0) {
+                                       // no in paramters
+                                       continue;
+                               }
+                       } else {
+                               if ((direction & 2) == 0) {
+                                       // no out paramters
+                                       continue;
+                               }
+                       }
+
                        if (!param.no_array_length && param.parameter_type is ArrayType) {
                                var array_type = (ArrayType) param.parameter_type;
                                
@@ -684,35 +806,37 @@ public class Vala.CCodeMethodModule : CCodeModule {
                        }
                }
 
-               if (!m.no_array_length && creturn_type is ArrayType) {
-                       // return array length if appropriate
-                       var array_type = (ArrayType) creturn_type;
+               if ((direction & 2) != 0) {
+                       if (!m.no_array_length && creturn_type is ArrayType) {
+                               // return array length if appropriate
+                               var array_type = (ArrayType) creturn_type;
 
-                       for (int dim = 1; dim <= array_type.rank; dim++) {
-                               var cparam = new CCodeFormalParameter (head.get_array_length_cname ("result", dim), "int*");
-                               cparam_map.set (codegen.get_param_pos (m.carray_length_parameter_position + 0.01 * dim), cparam);
-                               if (carg_map != null) {
-                                       carg_map.set (codegen.get_param_pos (m.carray_length_parameter_position + 0.01 * dim), new CCodeIdentifier (cparam.name));
+                               for (int dim = 1; dim <= array_type.rank; dim++) {
+                                       var cparam = new CCodeFormalParameter (head.get_array_length_cname ("result", dim), "int*");
+                                       cparam_map.set (codegen.get_param_pos (m.carray_length_parameter_position + 0.01 * dim), cparam);
+                                       if (carg_map != null) {
+                                               carg_map.set (codegen.get_param_pos (m.carray_length_parameter_position + 0.01 * dim), new CCodeIdentifier (cparam.name));
+                                       }
                                }
-                       }
-               } else if (creturn_type is DelegateType) {
-                       // return delegate target if appropriate
-                       var deleg_type = (DelegateType) creturn_type;
-                       var d = deleg_type.delegate_symbol;
-                       if (d.has_target) {
-                               var cparam = new CCodeFormalParameter (codegen.get_delegate_target_cname ("result"), "void*");
-                               cparam_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), cparam);
-                               if (carg_map != null) {
-                                       carg_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
+                       } else if (creturn_type is DelegateType) {
+                               // return delegate target if appropriate
+                               var deleg_type = (DelegateType) creturn_type;
+                               var d = deleg_type.delegate_symbol;
+                               if (d.has_target) {
+                                       var cparam = new CCodeFormalParameter (codegen.get_delegate_target_cname ("result"), "void*");
+                                       cparam_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), cparam);
+                                       if (carg_map != null) {
+                                               carg_map.set (codegen.get_param_pos (m.cdelegate_target_parameter_position), new CCodeIdentifier (cparam.name));
+                                       }
                                }
                        }
-               }
 
-               if (m.get_error_types ().size > 0) {
-                       var cparam = new CCodeFormalParameter ("error", "GError**");
-                       cparam_map.set (codegen.get_param_pos (-1), cparam);
-                       if (carg_map != null) {
-                               carg_map.set (codegen.get_param_pos (-1), new CCodeIdentifier (cparam.name));
+                       if (m.get_error_types ().size > 0) {
+                               var cparam = new CCodeFormalParameter ("error", "GError**");
+                               cparam_map.set (codegen.get_param_pos (-1), cparam);
+                               if (carg_map != null) {
+                                       carg_map.set (codegen.get_param_pos (-1), new CCodeIdentifier (cparam.name));
+                               }
                        }
                }
 
index 1029c299b99ccd45273be070b88cd70b1b544955..b8c8cec45fe3dc430139c6ca9bdf7e24c6bfcf2d 100644 (file)
@@ -100,8 +100,8 @@ public abstract class Vala.CCodeModule {
                next.visit_array_creation_expression (expr);
        }
 
-       public virtual void generate_cparameters (Method m, DataType creturn_type, bool in_gtypeinstance_creation_method, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null) {
-               next.generate_cparameters (m, creturn_type, in_gtypeinstance_creation_method, cparam_map, func, vdeclarator, carg_map, vcall);
+       public virtual void generate_cparameters (Method m, DataType creturn_type, bool in_gtypeinstance_creation_method, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
+               next.generate_cparameters (m, creturn_type, in_gtypeinstance_creation_method, cparam_map, func, vdeclarator, carg_map, vcall, direction);
        }
 
        public virtual string? get_custom_creturn_type (Method m) {
index c03fbfa6be96d6feaed5d4ba7fe16a29359d64b3..2d9c0a085551253ddbf88b5ff3231750c85bc2b4 100644 (file)
@@ -338,8 +338,8 @@ public class Vala.Method : Member {
         * @return the name to be used in C code
         */
        public virtual string get_real_cname () {
-               if (base_method != null || base_interface_method != null) {
-                       return "%s_real_%s".printf (parent_symbol.get_lower_case_cname (null), name);
+               if (base_method != null || base_interface_method != null || coroutine) {
+                       return "%sreal_%s".printf (parent_symbol.get_lower_case_cprefix (), name);
                } else {
                        return get_cname ();
                }