From: Mark Lee Date: Thu, 16 Jul 2009 06:33:39 +0000 (-0700) Subject: Add support for iterating over GValueArrays via foreach X-Git-Tag: 0.7.5~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3e2f5122592151a81079ccc7e410864c99edfecc;p=thirdparty%2Fvala.git Add support for iterating over GValueArrays via foreach Implements working support for using ValueArrays in foreach statements. Both owned and unowned Value element types are implemented, including a testcase. Example: void print_array (ValueArray array) { foreach (Value value in array) { message ("Value: %s", value.strdup_contents ()); } } Fixes bug 588742. --- diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 2ac63ba47..3b51d4289 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -107,6 +107,7 @@ internal class Vala.CCodeBaseModule : CCodeModule { public ErrorType gerror_type; public Class glist_type; public Class gslist_type; + public Class gvaluearray_type; public TypeSymbol gstringbuilder_type; public TypeSymbol garray_type; public TypeSymbol gbytearray_type; @@ -245,6 +246,7 @@ internal class Vala.CCodeBaseModule : CCodeModule { gerror_type = new ErrorType (null, null); glist_type = (Class) glib_ns.scope.lookup ("List"); gslist_type = (Class) glib_ns.scope.lookup ("SList"); + gvaluearray_type = (Class) glib_ns.scope.lookup ("ValueArray"); gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder"); garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array"); gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray"); diff --git a/codegen/valaccodecontrolflowmodule.vala b/codegen/valaccodecontrolflowmodule.vala index 86a98e3db..19a30a058 100644 --- a/codegen/valaccodecontrolflowmodule.vala +++ b/codegen/valaccodecontrolflowmodule.vala @@ -401,6 +401,60 @@ internal class Vala.CCodeControlFlowModule : CCodeMethodModule { cfor.add_initializer (new CCodeAssignment (get_variable_cexpression (it_name), get_variable_cexpression (collection_backup.name))); cfor.add_iterator (new CCodeAssignment (get_variable_cexpression (it_name), new CCodeMemberAccess.pointer (get_variable_cexpression (it_name), "next"))); + cblock.add_statement (cfor); + } else if (stmt.collection.value_type.compatible (new ObjectType (gvaluearray_type))) { + // iterating over a GValueArray + + var arr_index = "%s_index".printf (stmt.variable_name); + + if (current_method != null && current_method.coroutine) { + closure_struct.add_field (uint_type.get_cname (), arr_index); + } else { + var citdecl = new CCodeDeclaration (uint_type.get_cname ()); + var citvardecl = new CCodeVariableDeclarator (arr_index); + citvardecl.line = cblock.line; + citdecl.add_declarator (citvardecl); + cblock.add_statement (citdecl); + } + + var cbody = new CCodeBlock (); + + var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_get_nth")); + get_item.add_argument (get_variable_cexpression (collection_backup.name)); + get_item.add_argument (get_variable_cexpression (arr_index)); + + CCodeExpression element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_item); + + if (stmt.type_reference.value_owned) { + element_expr = get_ref_cexpression (stmt.type_reference, element_expr, null, new StructValueType (gvalue_type)); + } + + cfrag = new CCodeFragment (); + append_temp_decl (cfrag, temp_vars); + cbody.add_statement (cfrag); + temp_vars.clear (); + + if (current_method != null && current_method.coroutine) { + closure_struct.add_field (stmt.type_reference.get_cname (), stmt.variable_name); + cbody.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (stmt.variable_name), element_expr))); + } else { + var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ()); + var cvardecl = new CCodeVariableDeclarator (stmt.variable_name, element_expr); + cvardecl.line = cblock.line; + cdecl.add_declarator (cvardecl); + cbody.add_statement (cdecl); + } + + cbody.add_statement (stmt.body.ccodenode); + + var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (arr_index), new CCodeMemberAccess.pointer (get_variable_cexpression (collection_backup.name), "n_values")); + + var cfor = new CCodeForStatement (ccond, cbody); + + cfor.add_initializer (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0"))); + + cfor.add_iterator (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1")))); + cblock.add_statement (cfor); } diff --git a/tests/Makefile.am b/tests/Makefile.am index c5599ab3a..ad9bae5c1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -25,6 +25,7 @@ TESTS = \ control-flow/break.test \ control-flow/expressions-conditional.test \ control-flow/for.test \ + control-flow/foreach.test \ control-flow/switch.test \ control-flow/sideeffects.test \ enums/enums.test \ diff --git a/tests/control-flow/foreach.test b/tests/control-flow/foreach.test new file mode 100644 index 000000000..de8d1286b --- /dev/null +++ b/tests/control-flow/foreach.test @@ -0,0 +1,42 @@ + +Program: test + + +void test_owned (ValueArray array) { + uint i = 0; + + foreach (Value item in array) { + i++; + } + + assert (i == 3); +} + +void test_unowned (ValueArray array) { + uint i = 0; + + foreach (unowned Value item in array) { + i++; + } + + assert (i == 3); +} + +void test_foreach_gvaluearray () { + Value value; + ValueArray array = new ValueArray (3); + + value = 1; + array.append (value); + value = 2.0; + array.append (value); + value = "three"; + array.append (value); + + test_owned (array); + test_unowned (array); +} + +void main () { + test_foreach_gvaluearray (); +} diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala index 78836c136..c073ab908 100644 --- a/vala/valaforeachstatement.vala +++ b/vala/valaforeachstatement.vala @@ -180,6 +180,8 @@ public class Vala.ForeachStatement : Block { } return check_without_iterator (analyzer, collection_type, collection_type.get_type_arguments ().get (0)); + } else if (collection_type.compatible (analyzer.gvaluearray_type)) { + return check_without_iterator (analyzer, collection_type, analyzer.gvalue_type); } else { return check_with_iterator (analyzer, collection_type); } diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 38380f8a6..0b6febaa9 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -56,9 +56,11 @@ public class Vala.SemanticAnalyzer : CodeVisitor { public DataType double_type; public DataType type_type; public Class object_type; + public StructValueType gvalue_type; public DataType glist_type; public DataType gslist_type; public DataType garray_type; + public DataType gvaluearray_type; public Class gerror_type; public int next_lambda_id = 0; @@ -111,10 +113,12 @@ public class Vala.SemanticAnalyzer : CodeVisitor { object_type = (Class) glib_ns.scope.lookup ("Object"); type_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Type")); + gvalue_type = new StructValueType ((Struct) glib_ns.scope.lookup ("Value")); glist_type = new ObjectType ((Class) glib_ns.scope.lookup ("List")); gslist_type = new ObjectType ((Class) glib_ns.scope.lookup ("SList")); garray_type = new ObjectType ((Class) glib_ns.scope.lookup ("Array")); + gvaluearray_type = new ObjectType ((Class) glib_ns.scope.lookup ("ValueArray")); gerror_type = (Class) glib_ns.scope.lookup ("Error"); }