[vala] Arrays: Add experimental support for fixed-length arrays



commit e065e581748863cb7c90fabb2bb39d6671dfbe8f
Author: Jürg Billeter <j bitron ch>
Date:   Fri Apr 10 17:02:22 2009 +0200

    Arrays: Add experimental support for fixed-length arrays
    
    Local fixed-length arrays are allocated on the stack.
    
        int[3] array = { 1, 2, 3 };
    
    Fixes bug 492481.
---
 ccode/valaccodevariabledeclarator.vala  |   14 +++-
 gobject/valaccodearraymodule.vala       |  169 ++++++++++++++++++++++++++++++-
 gobject/valaccodeassignmentmodule.vala  |   24 ++++-
 gobject/valaccodebasemodule.vala        |  128 +++++++++++++++--------
 gobject/valaccodecontrolflowmodule.vala |   11 ++-
 gobject/valaccodestructmodule.vala      |   43 ++++++---
 vala/valaarraytype.vala                 |   28 +++++-
 vala/valadatatype.vala                  |    4 +
 vala/valaparser.vala                    |   19 +++-
 9 files changed, 370 insertions(+), 70 deletions(-)

diff --git a/ccode/valaccodevariabledeclarator.vala b/ccode/valaccodevariabledeclarator.vala
index c28704d..fdb9dfa 100644
--- a/ccode/valaccodevariabledeclarator.vala
+++ b/ccode/valaccodevariabledeclarator.vala
@@ -36,13 +36,22 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator {
 	 */
 	public CCodeExpression? initializer { get; set; }
 
-	public CCodeVariableDeclarator (string name, CCodeExpression? initializer = null) {
+	/**
+	 * The optional declarator suffix.
+	 */
+	public string? declarator_suffix { get; set; }
+
+	public CCodeVariableDeclarator (string name, CCodeExpression? initializer = null, string? declarator_suffix = null) {
 		this.name = name;
 		this.initializer = initializer;
+		this.declarator_suffix = declarator_suffix;
 	}
 
 	public override void write (CCodeWriter writer) {
 		writer.write_string (name);
+		if (declarator_suffix != null) {
+			writer.write_string (declarator_suffix);
+		}
 
 		if (initializer != null) {
 			writer.write_string (" = ");
@@ -52,6 +61,9 @@ public class Vala.CCodeVariableDeclarator : CCodeDeclarator {
 
 	public override void write_declaration (CCodeWriter writer) {
 		writer.write_string (name);
+		if (declarator_suffix != null) {
+			writer.write_string (declarator_suffix);
+		}
 
 		// initializer lists can't be moved to a separate statement
 		if (initializer is CCodeInitializerList) {
diff --git a/gobject/valaccodearraymodule.vala b/gobject/valaccodearraymodule.vala
index f1a9ba8..2143f3f 100644
--- a/gobject/valaccodearraymodule.vala
+++ b/gobject/valaccodearraymodule.vala
@@ -46,6 +46,26 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule {
 	public override void visit_array_creation_expression (ArrayCreationExpression expr) {
 		expr.accept_children (codegen);
 
+		var array_type = expr.target_type as ArrayType;
+		if (array_type != null && array_type.fixed_length) {
+			// no heap allocation for fixed-length arrays
+
+			var ce = new CCodeCommaExpression ();
+			var temp_var = get_temp_variable (array_type, true, expr);
+			var name_cnode = new CCodeIdentifier (temp_var.name);
+			int i = 0;
+
+			temp_vars.insert (0, temp_var);
+
+			append_initializer_list (ce, name_cnode, expr.initializer_list, expr.rank, ref i);
+
+			ce.append_expression (name_cnode);
+
+			expr.ccodenode = ce;
+
+			return;
+		}
+
 		var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
 		gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ()));
 		bool first = true;
@@ -105,9 +125,14 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule {
 	}
 
 	public override CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
+		var array_type = array_expr.value_type as ArrayType;
+
+		if (array_type != null && array_type.fixed_length) {
+			return new CCodeConstant (array_type.length.to_string ());
+		}
+
 		// dim == -1 => total size over all dimensions
 		if (dim == -1) {
-			var array_type = array_expr.value_type as ArrayType;
 			if (array_type != null && array_type.rank > 1) {
 				CCodeExpression cexpr = get_array_length_cexpression (array_expr, 1);
 				for (dim = 2; dim <= array_type.rank; dim++) {
@@ -370,7 +395,9 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule {
 	}
 
 	public override void append_vala_array_free () {
-		var fun = new CCodeFunction ("_vala_array_free", "void");
+		// _vala_array_destroy only frees elements but not the array itself
+
+		var fun = new CCodeFunction ("_vala_array_destroy", "void");
 		fun.modifiers = CCodeModifiers.STATIC;
 		fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
 		fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
@@ -391,6 +418,26 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule {
 		fun.block = new CCodeBlock ();
 		fun.block.add_statement (cif);
 
+		source_type_member_definition.append (fun);
+
+		// _vala_array_free frees elements and array
+
+		fun = new CCodeFunction ("_vala_array_free", "void");
+		fun.modifiers = CCodeModifiers.STATIC;
+		fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
+		fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
+		fun.add_parameter (new CCodeFormalParameter ("destroy_func", "GDestroyNotify"));
+		source_declarations.add_type_member_declaration (fun.copy ());
+
+		// call _vala_array_destroy to free the array elements
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
+		ccall.add_argument (new CCodeIdentifier ("array"));
+		ccall.add_argument (new CCodeIdentifier ("array_length"));
+		ccall.add_argument (new CCodeIdentifier ("destroy_func"));
+
+		fun.block = new CCodeBlock ();
+		fun.block.add_statement (new CCodeExpressionStatement (ccall));
+
 		var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
 		carrfree.add_argument (new CCodeIdentifier ("array"));
 		fun.block.add_statement (new CCodeExpressionStatement (carrfree));
@@ -480,14 +527,69 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule {
 		source_type_member_definition.append (fun);
 	}
 
+	public override CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
+		if (expression_type is ArrayType) {
+			var array_type = (ArrayType) expression_type;
+
+			if (!array_type.fixed_length) {
+				return base.get_ref_cexpression (expression_type, cexpr, expr, node);
+			}
+
+			var decl = get_temp_variable (expression_type, false, node);
+			temp_vars.insert (0, decl);
+
+			var ctemp = get_variable_cexpression (decl.name);
+
+			var copy_call = new CCodeFunctionCall (new CCodeIdentifier (generate_array_copy_wrapper (array_type)));
+			copy_call.add_argument (cexpr);
+			copy_call.add_argument (ctemp);
+
+			var ccomma = new CCodeCommaExpression ();
+
+			ccomma.append_expression (copy_call);
+			ccomma.append_expression (ctemp);
+
+			return ccomma;
+		} else {
+			return base.get_ref_cexpression (expression_type, cexpr, expr, node);
+		}
+	}
+
 	public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference) {
 		if (type is ArrayType) {
-			return new CCodeIdentifier (generate_array_dup_wrapper ((ArrayType) type));
+			var array_type = (ArrayType) type;
+			// fixed length arrays use different code
+			// generated by overridden get_ref_cexpression method
+			assert (!array_type.fixed_length);
+			return new CCodeIdentifier (generate_array_dup_wrapper (array_type));
 		} else {
 			return base.get_dup_func_expression (type, source_reference);
 		}
 	}
 
+	public override CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr) {
+		if (type is ArrayType) {
+			var array_type = (ArrayType) type;
+
+			if (!array_type.fixed_length) {
+				return base.get_unref_expression (cvar, type, expr);
+			}
+
+			requires_array_free = true;
+
+			var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
+
+			ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
+			ccall.add_argument (cvar);
+			ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length)));
+			ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
+
+			return ccall;
+		} else {
+			return base.get_unref_expression (cvar, type, expr);
+		}
+	}
+
 	string generate_array_dup_wrapper (ArrayType array_type) {
 		string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
 
@@ -560,6 +662,67 @@ internal class Vala.CCodeArrayModule : CCodeMethodCallModule {
 		return dup_func;
 	}
 
+	string generate_array_copy_wrapper (ArrayType array_type) {
+		string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id);
+
+		if (!add_wrapper (dup_func)) {
+			// wrapper already defined
+			return dup_func;
+		}
+
+		// declaration
+
+		var function = new CCodeFunction (dup_func, "void");
+		function.modifiers = CCodeModifiers.STATIC;
+
+		function.add_parameter (new CCodeFormalParameter ("self", array_type.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("dest", array_type.get_cname () + "*"));
+
+		// definition
+
+		var block = new CCodeBlock ();
+
+		if (requires_copy (array_type.element_type)) {
+			var old_temp_vars = temp_vars;
+
+			var idx_decl = new CCodeDeclaration ("int");
+			idx_decl.add_declarator (new CCodeVariableDeclarator ("i"));
+			block.add_statement (idx_decl);
+
+			var loop_body = new CCodeBlock ();
+			loop_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("dest"), new CCodeIdentifier ("i")), get_ref_cexpression (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), null, array_type))));
+
+			var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeConstant ("%d".printf (array_type.length))), loop_body);
+			cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
+			cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
+			block.add_statement (cfor);
+
+			var cfrag = new CCodeFragment ();
+			append_temp_decl (cfrag, temp_vars);
+			block.add_statement (cfrag);
+			temp_vars = old_temp_vars;
+		} else {
+			var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+			dup_call.add_argument (new CCodeIdentifier ("dest"));
+			dup_call.add_argument (new CCodeIdentifier ("self"));
+
+			var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+			sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+			dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call));
+
+			block.add_statement (new CCodeExpressionStatement (dup_call));
+		}
+
+		// append to file
+
+		source_declarations.add_type_member_declaration (function.copy ());
+
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return dup_func;
+	}
+
 	string generate_array_add_wrapper (ArrayType array_type) {
 		string add_func = "_vala_array_add%d".printf (++next_array_add_id);
 
diff --git a/gobject/valaccodeassignmentmodule.vala b/gobject/valaccodeassignmentmodule.vala
index fa64ccc..4470628 100644
--- a/gobject/valaccodeassignmentmodule.vala
+++ b/gobject/valaccodeassignmentmodule.vala
@@ -208,6 +208,23 @@ internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
 		return codenode;
 	}
 
+	CCodeExpression emit_fixed_length_array_assignment (Assignment assignment, ArrayType array_type) {
+		CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
+		CCodeExpression lhs = (CCodeExpression) get_ccodenode (assignment.left);
+
+		// it is necessary to use memcpy for fixed-length (stack-allocated) arrays
+		// simple assignments do not work in C
+		var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+		sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+		var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
+		var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+		ccopy.add_argument (lhs);
+		ccopy.add_argument (rhs);
+		ccopy.add_argument (size);
+
+		return ccopy;
+	}
+
 	public override void visit_assignment (Assignment assignment) {
 		assignment.right.accept (codegen);
 
@@ -219,7 +236,12 @@ internal class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
 		if (assignment.left.symbol_reference is Property) {
 			assignment.ccodenode = emit_property_assignment (assignment);
 		} else {
-			assignment.ccodenode = emit_simple_assignment (assignment);
+			var array_type = assignment.left.value_type as ArrayType;
+			if (array_type != null && array_type.fixed_length) {
+				assignment.ccodenode = emit_fixed_length_array_assignment (assignment, array_type);
+			} else {
+				assignment.ccodenode = emit_simple_assignment (assignment);
+			}
 		}
 	}
 }
diff --git a/gobject/valaccodebasemodule.vala b/gobject/valaccodebasemodule.vala
index e11eece..a4e5506 100644
--- a/gobject/valaccodebasemodule.vala
+++ b/gobject/valaccodebasemodule.vala
@@ -1480,15 +1480,17 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		if (local.variable_type is ArrayType) {
 			// create variables to store array dimensions
 			var array_type = (ArrayType) local.variable_type;
-			
-			for (int dim = 1; dim <= array_type.rank; dim++) {
-				var len_var = new LocalVariable (int_type.copy (), head.get_array_length_cname (get_variable_cname (local.name), dim));
-				temp_vars.insert (0, len_var);
-			}
 
-			if (array_type.rank == 1) {
-				var size_var = new LocalVariable (int_type.copy (), head.get_array_size_cname (get_variable_cname (local.name)));
-				temp_vars.insert (0, size_var);
+			if (!array_type.fixed_length) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					var len_var = new LocalVariable (int_type.copy (), head.get_array_length_cname (get_variable_cname (local.name), dim));
+					temp_vars.insert (0, len_var);
+				}
+
+				if (array_type.rank == 1) {
+					var size_var = new LocalVariable (int_type.copy (), head.get_array_size_cname (get_variable_cname (local.name)));
+					temp_vars.insert (0, size_var);
+				}
 			}
 		} else if (local.variable_type is DelegateType) {
 			var deleg_type = (DelegateType) local.variable_type;
@@ -1507,26 +1509,30 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 			if (local.variable_type is ArrayType) {
 				var array_type = (ArrayType) local.variable_type;
 
-				var ccomma = new CCodeCommaExpression ();
+				if (array_type.fixed_length) {
+					rhs = null;
+				} else {
+					var ccomma = new CCodeCommaExpression ();
 
-				var temp_var = get_temp_variable (local.variable_type, true, local);
-				temp_vars.insert (0, temp_var);
-				ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), rhs));
+					var temp_var = get_temp_variable (local.variable_type, true, local);
+					temp_vars.insert (0, temp_var);
+					ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), rhs));
 
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					var lhs_array_len = get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim));
-					var rhs_array_len = head.get_array_length_cexpression (local.initializer, dim);
-					ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
-				}
-				if (array_type.rank == 1) {
-					var lhs_array_size = get_variable_cexpression (head.get_array_size_cname (get_variable_cname (local.name)));
-					var rhs_array_len = get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), 1));
-					ccomma.append_expression (new CCodeAssignment (lhs_array_size, rhs_array_len));
-				}
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						var lhs_array_len = get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim));
+						var rhs_array_len = head.get_array_length_cexpression (local.initializer, dim);
+						ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
+					}
+					if (array_type.rank == 1) {
+						var lhs_array_size = get_variable_cexpression (head.get_array_size_cname (get_variable_cname (local.name)));
+						var rhs_array_len = get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), 1));
+						ccomma.append_expression (new CCodeAssignment (lhs_array_size, rhs_array_len));
+					}
 				
-				ccomma.append_expression (get_variable_cexpression (temp_var.name));
+					ccomma.append_expression (get_variable_cexpression (temp_var.name));
 				
-				rhs = ccomma;
+					rhs = ccomma;
+				}
 			} else if (local.variable_type is DelegateType) {
 				var deleg_type = (DelegateType) local.variable_type;
 				var d = deleg_type.delegate_symbol;
@@ -1553,15 +1559,19 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 				// initialize array length variables
 				var array_type = (ArrayType) local.variable_type;
 
-				var ccomma = new CCodeCommaExpression ();
+				if (array_type.fixed_length) {
+					rhs = null;
+				} else {
+					var ccomma = new CCodeCommaExpression ();
 
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim)), new CCodeConstant ("0")));
-				}
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (head.get_array_length_cname (get_variable_cname (local.name), dim)), new CCodeConstant ("0")));
+					}
 
-				ccomma.append_expression (rhs);
+					ccomma.append_expression (rhs);
 
-				rhs = ccomma;
+					rhs = ccomma;
+				}
 			}
 		}
 
@@ -1573,13 +1583,13 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		}
 
 		if (current_method != null && current_method.coroutine) {
-			closure_struct.add_field (local.variable_type.get_cname (), get_variable_cname (local.name));
+			closure_struct.add_field (local.variable_type.get_cname (), get_variable_cname (local.name) + local.variable_type.get_cdeclarator_suffix ());
 
 			if (local.initializer != null) {
 				cfrag.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_variable_cname (local.name)), rhs)));
 			}
 		} else {
-			var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs);
+			var cvar = new CCodeVariableDeclarator (get_variable_cname (local.name), rhs, local.variable_type.get_cdeclarator_suffix ());
 
 			var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
 			cdecl.add_declarator (cvar);
@@ -1592,6 +1602,24 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 			}
 		}
 
+		if (local.initializer != null && local.variable_type is ArrayType) {
+			var array_type = (ArrayType) local.variable_type;
+
+			if (array_type.fixed_length) {
+				// it is necessary to use memcpy for fixed-length (stack-allocated) arrays
+				// simple assignments do not work in C
+				var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+				sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+				var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
+
+				var ccopy = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+				ccopy.add_argument (get_variable_cexpression (local.name));
+				ccopy.add_argument ((CCodeExpression) local.initializer.ccodenode);
+				ccopy.add_argument (size);
+				cfrag.append (new CCodeExpressionStatement (ccopy));
+			}
+		}
+
 		if (local.initializer != null && local.initializer.tree_can_fail) {
 			head.add_simple_check (local.initializer, cfrag);
 		}
@@ -1883,7 +1911,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		return destroy_func;
 	}
 
-	public CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr) {
+	public virtual CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr) {
 		var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
 
 		if (type is ValueType && !type.nullable) {
@@ -1938,8 +1966,8 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 			if (array_type.element_type.data_type == null || array_type.element_type.data_type.is_reference_type ()) {
 				requires_array_free = true;
 
-				bool first = true;
 				CCodeExpression csizeexpr = null;
+				bool first = true;
 				for (int dim = 1; dim <= array_type.rank; dim++) {
 					if (first) {
 						csizeexpr = head.get_array_length_cexpression (expr, dim);
@@ -2029,27 +2057,29 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 			} else {
 				var cdecl = new CCodeDeclaration (local.variable_type.get_cname ());
 		
-				var vardecl = new CCodeVariableDeclarator (local.name);
+				var vardecl = new CCodeVariableDeclarator (local.name, null, local.variable_type.get_cdeclarator_suffix ());
 				// sets #line
 				local.ccodenode = vardecl;
 				cdecl.add_declarator (vardecl);
 
 				var st = local.variable_type.data_type as Struct;
+				var array_type = local.variable_type as ArrayType;
 
 				if (local.name.has_prefix ("*")) {
 					// do not dereference unintialized variable
 					// initialization is not needed for these special
 					// pointer temp variables
 					// used to avoid side-effects in assignments
-				} else if (local.variable_type.is_reference_type_or_type_parameter ()) {
-					vardecl.initializer = new CCodeConstant ("NULL");
-				} else if (st != null && !st.is_simple_type ()) {
+				} else if ((st != null && !st.is_simple_type ()) ||
+				           (array_type != null && array_type.fixed_length)) {
 					// 0-initialize struct with struct initializer { 0 }
 					// necessary as they will be passed by reference
 					var clist = new CCodeInitializerList ();
 					clist.append (new CCodeConstant ("0"));
 
 					vardecl.initializer = clist;
+				} else if (local.variable_type.is_reference_type_or_type_parameter ()) {
+					vardecl.initializer = new CCodeConstant ("NULL");
 				}
 			
 				cfrag.append (cdecl);
@@ -2530,6 +2560,11 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 			return false;
 		}
 
+		var array_type = type as ArrayType;
+		if (array_type != null && array_type.fixed_length) {
+			return requires_destroy (array_type.element_type);
+		}
+
 		var cl = type.data_type as Class;
 		if (cl != null && cl.is_reference_counting ()
 		    && cl.get_unref_function () == "") {
@@ -2555,7 +2590,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 		}
 	}
 
-	public CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
+	public virtual CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
 		if (expression_type is ValueType && !expression_type.nullable) {
 			// normal value type, no null check
 			// (copy (&expr, &temp), temp)
@@ -3678,17 +3713,20 @@ internal class Vala.CCodeBaseModule : CCodeModule {
 	}
 
 	public CCodeExpression? default_value_for_type (DataType type, bool initializer_expression) {
-		if ((type.data_type != null && type.data_type.is_reference_type ())
-		    || type is PointerType || type is ArrayType || type is DelegateType) {
-			return new CCodeConstant ("NULL");
-		} else if (type.data_type != null && type.data_type.get_default_value () != null) {
-			return new CCodeConstant (type.data_type.get_default_value ());
-		} else if (type.data_type is Struct && initializer_expression) {
+		var array_type = type as ArrayType;
+		if (initializer_expression && (type.data_type is Struct ||
+		    (array_type != null && array_type.fixed_length))) {
 			// 0-initialize struct with struct initializer { 0 }
 			// only allowed as initializer expression in C
 			var clist = new CCodeInitializerList ();
 			clist.append (new CCodeConstant ("0"));
 			return clist;
+		} else if ((type.data_type != null && type.data_type.is_reference_type ())
+		           || type is PointerType || type is DelegateType
+		           || (array_type != null && !array_type.fixed_length)) {
+			return new CCodeConstant ("NULL");
+		} else if (type.data_type != null && type.data_type.get_default_value () != null) {
+			return new CCodeConstant (type.data_type.get_default_value ());
 		} else if (type.type_parameter != null) {
 			return new CCodeConstant ("NULL");
 		} else if (type is ErrorType) {
diff --git a/gobject/valaccodecontrolflowmodule.vala b/gobject/valaccodecontrolflowmodule.vala
index a9348d9..fda6f46 100644
--- a/gobject/valaccodecontrolflowmodule.vala
+++ b/gobject/valaccodecontrolflowmodule.vala
@@ -1,6 +1,7 @@
 /* valaccodecontrolflowmodule.vala
  *
- * Copyright (C) 2006-2008  Jürg Billeter, Raffaele Sandrini
+ * Copyright (C) 2006-2009  Jürg Billeter
+ * Copyright (C) 2006-2008  Raffaele Sandrini
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -282,6 +283,12 @@ internal class Vala.CCodeControlFlowModule : CCodeMethodModule {
 		var collection_backup = stmt.collection_variable;
 		var collection_type = collection_backup.variable_type.copy ();
 
+		var array_type = collection_type as ArrayType;
+		if (array_type != null) {
+			// avoid assignment issues
+			array_type.fixed_length = false;
+		}
+
 		if (current_method != null && current_method.coroutine) {
 			closure_struct.add_field (collection_type.get_cname (), collection_backup.name);
 			cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode)));
@@ -301,7 +308,7 @@ internal class Vala.CCodeControlFlowModule : CCodeMethodModule {
 		}
 
 		if (stmt.collection.value_type is ArrayType) {
-			var array_type = (ArrayType) stmt.collection.value_type;
+			array_type = (ArrayType) stmt.collection.value_type;
 			
 			var array_len = head.get_array_length_cexpression (stmt.collection);
 
diff --git a/gobject/valaccodestructmodule.vala b/gobject/valaccodestructmodule.vala
index bbc2c94..b45578c 100644
--- a/gobject/valaccodestructmodule.vala
+++ b/gobject/valaccodestructmodule.vala
@@ -45,18 +45,21 @@ internal class Vala.CCodeStructModule : CCodeBaseModule {
 			if (f.binding == MemberBinding.INSTANCE)  {
 				generate_type_declaration (f.field_type, decl_space);
 
-				instance_struct.add_field (field_ctype, f.get_cname ());
+				instance_struct.add_field (field_ctype, f.get_cname () + f.field_type.get_cdeclarator_suffix ());
 				if (f.field_type is ArrayType && !f.no_array_length) {
 					// create fields to store array dimensions
 					var array_type = (ArrayType) f.field_type;
-					var len_type = int_type.copy ();
 
-					for (int dim = 1; dim <= array_type.rank; dim++) {
-						instance_struct.add_field (len_type.get_cname (), head.get_array_length_cname (f.name, dim));
-					}
+					if (!array_type.fixed_length) {
+						var len_type = int_type.copy ();
+
+						for (int dim = 1; dim <= array_type.rank; dim++) {
+							instance_struct.add_field (len_type.get_cname (), head.get_array_length_cname (f.name, dim));
+						}
 
-					if (array_type.rank == 1 && f.is_internal_symbol ()) {
-						instance_struct.add_field (len_type.get_cname (), head.get_array_size_cname (f.name));
+						if (array_type.rank == 1 && f.is_internal_symbol ()) {
+							instance_struct.add_field (len_type.get_cname (), head.get_array_size_cname (f.name));
+						}
 					}
 				} else if (f.field_type is DelegateType) {
 					var delegate_type = (DelegateType) f.field_type;
@@ -201,14 +204,28 @@ internal class Vala.CCodeStructModule : CCodeBaseModule {
 					copy = get_ref_cexpression (f.field_type, copy, ma, f);
 				}
 				var dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), f.name);
-				cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest, copy)));
 
 				var array_type = f.field_type as ArrayType;
-				if (array_type != null) {
-					for (int dim = 1; dim <= array_type.rank; dim++) {
-						var len_src = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_array_length_cname (f.name, dim));
-						var len_dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), get_array_length_cname (f.name, dim));
-						cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (len_dest, len_src)));
+				if (array_type != null && array_type.fixed_length) {
+					// fixed-length (stack-allocated) arrays
+					var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+					sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+					var size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call);
+
+					var array_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
+					array_copy_call.add_argument (dest);
+					array_copy_call.add_argument (copy);
+					array_copy_call.add_argument (size);
+					cblock.add_statement (new CCodeExpressionStatement (array_copy_call));
+				} else {
+					cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest, copy)));
+
+					if (array_type != null) {
+						for (int dim = 1; dim <= array_type.rank; dim++) {
+							var len_src = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), get_array_length_cname (f.name, dim));
+							var len_dest = new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest"), get_array_length_cname (f.name, dim));
+							cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (len_dest, len_src)));
+						}
 					}
 				}
 			}
diff --git a/vala/valaarraytype.vala b/vala/valaarraytype.vala
index 1534c6d..4711555 100644
--- a/vala/valaarraytype.vala
+++ b/vala/valaarraytype.vala
@@ -37,6 +37,13 @@ public class Vala.ArrayType : ReferenceType {
 		}
 	}
 
+	public bool fixed_length { get; set; }
+
+	/**
+	 * The length of this fixed-length array.
+	 */
+	public int length { get; set; }
+
 	/**
 	 * The rank of this array.
 	 */
@@ -127,13 +134,30 @@ public class Vala.ArrayType : ReferenceType {
 		result.value_owned = value_owned;
 		result.nullable = nullable;
 		result.floating_reference = floating_reference;
-		
+
+		if (fixed_length) {
+			result.fixed_length = true;
+			result.length = length;
+		}
+
 		return result;
 	}
 
 	public override string? get_cname () {
 		// FIXME add support for [Immutable] or [Const] attribute to support arrays to const data
-		return element_type.get_cname () + "*";
+		if (fixed_length) {
+			return element_type.get_cname ();
+		} else {
+			return element_type.get_cname () + "*";
+		}
+	}
+
+	public override string get_cdeclarator_suffix () {
+		if (fixed_length) {
+			return "[%d]".printf (length);
+		} else {
+			return "";
+		}
 	}
 
 	public override bool is_array () {
diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala
index 68199e8..45af866 100644
--- a/vala/valadatatype.vala
+++ b/vala/valadatatype.vala
@@ -118,6 +118,10 @@ public abstract class Vala.DataType : CodeNode {
 		return null;
 	}
 
+	public virtual string get_cdeclarator_suffix () {
+		return "";
+	}
+
 	/**
 	 * Returns the name and qualifiers of this type as it is used in C code
 	 * in a const declaration.
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index ee9e696..ab11ad1 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -422,13 +422,18 @@ public class Vala.Parser : CodeVisitor {
 		// this is more logical, especially when nullable arrays
 		// or pointers are involved
 		while (accept (TokenType.OPEN_BRACKET)) {
+			int array_length = -1;
 			int array_rank = 0;
 			do {
 				array_rank++;
 				// support for stack-allocated arrays
 				// also required for decision between expression and declaration statement
 				if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
-					parse_expression ();
+					var length_expression = parse_expression ();
+					var length_literal = length_expression as IntegerLiteral;
+					if (length_literal != null) {
+						array_length = length_literal.value.to_int ();
+					}
 				}
 			}
 			while (accept (TokenType.COMMA));
@@ -437,8 +442,16 @@ public class Vala.Parser : CodeVisitor {
 			// arrays contain strong references by default
 			type.value_owned = true;
 
-			type = new ArrayType (type, array_rank, get_src (begin));
-			type.nullable = accept (TokenType.INTERR);
+			var array_type = new ArrayType (type, array_rank, get_src (begin));
+			array_type.nullable = accept (TokenType.INTERR);
+
+			if (array_rank == 1 && array_length > 0) {
+				// fixed length (stack-allocated) array
+				array_type.fixed_length = true;
+				array_type.length = array_length;
+			}
+
+			type = array_type;
 		}
 
 		if (accept (TokenType.OP_NEG)) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]