Commit e065e581 authored by Jürg Billeter's avatar Jürg Billeter

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.
parent 157662d5
......@@ -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) {
......
......@@ -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);
......
......@@ -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);
}
}
}
}
......@@ -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) {
......
/* 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);
......
......@@ -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)));
}
}
}
}
......
......@@ -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 () {
......
......@@ -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.
......
......@@ -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 ();
}
}
}