glib-2.0: Add default arguments to g_option_context_new binding
[vala-lang.git] / codegen / valaccodearraymodule.vala
blob6ab425667dbbab950fe972eff3f65e0b2afbd765
1 /* valaccodearraymodule.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using Gee;
27 internal class Vala.CCodeArrayModule : CCodeMethodCallModule {
28 int next_array_dup_id = 0;
29 int next_array_add_id = 0;
31 public CCodeArrayModule (CCodeGenerator codegen, CCodeModule? next) {
32 base (codegen, next);
35 void append_initializer_list (CCodeCommaExpression ce, CCodeExpression name_cnode, InitializerList initializer_list, int rank, ref int i) {
36 foreach (Expression e in initializer_list.get_initializers ()) {
37 if (rank > 1) {
38 append_initializer_list (ce, name_cnode, (InitializerList) e, rank - 1, ref i);
39 } else {
40 ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
41 i++;
46 public override void visit_array_creation_expression (ArrayCreationExpression expr) {
47 expr.accept_children (codegen);
49 var array_type = expr.target_type as ArrayType;
50 if (array_type != null && array_type.fixed_length) {
51 // no heap allocation for fixed-length arrays
53 var ce = new CCodeCommaExpression ();
54 var temp_var = get_temp_variable (array_type, true, expr);
55 var name_cnode = get_variable_cexpression (temp_var.name);
56 int i = 0;
58 temp_vars.insert (0, temp_var);
60 append_initializer_list (ce, name_cnode, expr.initializer_list, expr.rank, ref i);
62 ce.append_expression (name_cnode);
64 expr.ccodenode = ce;
66 return;
69 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
70 gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ()));
71 bool first = true;
72 CCodeExpression cexpr = null;
74 // iterate over each dimension
75 foreach (Expression size in expr.get_sizes ()) {
76 CCodeExpression csize = (CCodeExpression) size.ccodenode;
78 if (!is_pure_ccode_expression (csize)) {
79 var temp_var = get_temp_variable (int_type, false, expr);
80 var name_cnode = get_variable_cexpression (temp_var.name);
81 size.ccodenode = name_cnode;
83 temp_vars.insert (0, temp_var);
85 csize = new CCodeAssignment (name_cnode, csize);
88 if (first) {
89 cexpr = csize;
90 first = false;
91 } else {
92 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, csize);
96 // add extra item to have array NULL-terminated for all reference types
97 if (expr.element_type.data_type != null && expr.element_type.data_type.is_reference_type ()) {
98 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cexpr, new CCodeConstant ("1"));
101 gnew.add_argument (cexpr);
103 if (expr.initializer_list != null) {
104 var ce = new CCodeCommaExpression ();
105 var temp_var = get_temp_variable (expr.value_type, true, expr);
106 var name_cnode = get_variable_cexpression (temp_var.name);
107 int i = 0;
109 temp_vars.insert (0, temp_var);
111 ce.append_expression (new CCodeAssignment (name_cnode, gnew));
113 append_initializer_list (ce, name_cnode, expr.initializer_list, expr.rank, ref i);
115 ce.append_expression (name_cnode);
117 expr.ccodenode = ce;
118 } else {
119 expr.ccodenode = gnew;
123 public override string get_array_length_cname (string array_cname, int dim) {
124 return "%s_length%d".printf (array_cname, dim);
127 public override CCodeExpression get_array_length_cexpression (Expression array_expr, int dim = -1) {
128 var array_type = array_expr.value_type as ArrayType;
130 if (array_type != null && array_type.fixed_length) {
131 return new CCodeConstant (array_type.length.to_string ());
134 // dim == -1 => total size over all dimensions
135 if (dim == -1) {
136 if (array_type != null && array_type.rank > 1) {
137 CCodeExpression cexpr = get_array_length_cexpression (array_expr, 1);
138 for (dim = 2; dim <= array_type.rank; dim++) {
139 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cexpr, get_array_length_cexpression (array_expr, dim));
141 return cexpr;
142 } else {
143 dim = 1;
147 bool is_out = false;
149 if (array_expr is UnaryExpression) {
150 var unary_expr = (UnaryExpression) array_expr;
151 if (unary_expr.operator == UnaryOperator.OUT || unary_expr.operator == UnaryOperator.REF) {
152 array_expr = unary_expr.inner;
153 is_out = true;
155 } else if (array_expr is ReferenceTransferExpression) {
156 var reftransfer_expr = (ReferenceTransferExpression) array_expr;
157 array_expr = reftransfer_expr.inner;
160 if (array_expr is ArrayCreationExpression) {
161 Gee.List<Expression> size = ((ArrayCreationExpression) array_expr).get_sizes ();
162 var length_expr = size[dim - 1];
163 return (CCodeExpression) get_ccodenode (length_expr);
164 } else if (array_expr is MethodCall || array_expr is CastExpression) {
165 Gee.List<CCodeExpression> size = array_expr.get_array_sizes ();
166 if (size.size >= dim) {
167 return size[dim - 1];
169 } else if (array_expr.symbol_reference != null) {
170 if (array_expr.symbol_reference is FormalParameter) {
171 var param = (FormalParameter) array_expr.symbol_reference;
172 if (param.captured) {
173 // captured variables are stored on the heap
174 var block = ((Method) param.parent_symbol).body;
175 var length_expr = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_length_cname (get_variable_cname (param.name), dim));
176 if (is_out) {
177 // passing array as out/ref
178 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
179 } else {
180 return length_expr;
182 } else if (current_method != null && current_method.coroutine) {
183 var length_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_array_length_cname (get_variable_cname (param.name), dim));
184 if (is_out) {
185 // passing array as out/ref
186 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
187 } else {
188 return length_expr;
190 } else {
191 if (param.array_null_terminated) {
192 var carray_expr = get_variable_cexpression (param.name);
193 requires_array_length = true;
194 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
195 len_call.add_argument (carray_expr);
196 return len_call;
197 } else if (!param.no_array_length) {
198 CCodeExpression length_expr = get_variable_cexpression (get_array_length_cname (get_variable_cname (param.name), dim));
199 if (param.direction != ParameterDirection.IN) {
200 // accessing argument of out/ref param
201 length_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, length_expr);
203 if (is_out) {
204 // passing array as out/ref
205 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
206 } else {
207 return length_expr;
211 } else if (array_expr.symbol_reference is LocalVariable) {
212 var local = (LocalVariable) array_expr.symbol_reference;
213 if (local.captured) {
214 // captured variables are stored on the heap
215 var block = (Block) local.parent_symbol;
216 var length_expr = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_length_cname (get_variable_cname (local.name), dim));
217 if (is_out) {
218 // passing array as out/ref
219 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
220 } else {
221 return length_expr;
223 } else if (current_method != null && current_method.coroutine) {
224 var length_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), get_array_length_cname (get_variable_cname (local.name), dim));
225 if (is_out) {
226 // passing array as out/ref
227 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
228 } else {
229 return length_expr;
231 } else {
232 var length_expr = get_variable_cexpression (get_array_length_cname (get_variable_cname (local.name), dim));
233 if (is_out) {
234 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
235 } else {
236 return length_expr;
239 } else if (array_expr.symbol_reference is Field) {
240 var field = (Field) array_expr.symbol_reference;
241 if (field.array_null_terminated) {
242 var ma = (MemberAccess) array_expr;
244 CCodeExpression carray_expr = null;
246 if (field.binding == MemberBinding.INSTANCE) {
247 var cl = field.parent_symbol as Class;
248 bool is_gtypeinstance = (cl != null && !cl.is_compact);
250 string array_cname = field.get_cname ();
251 CCodeExpression typed_inst = (CCodeExpression) get_ccodenode (ma.inner);
253 CCodeExpression inst;
254 if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) {
255 inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
256 } else {
257 inst = typed_inst;
259 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
260 carray_expr = new CCodeMemberAccess.pointer (inst, array_cname);
261 } else {
262 carray_expr = new CCodeMemberAccess (inst, array_cname);
264 } else {
265 carray_expr = new CCodeIdentifier (field.get_cname ());
268 requires_array_length = true;
269 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
270 len_call.add_argument (carray_expr);
271 return len_call;
272 } else if (!field.no_array_length) {
273 var ma = (MemberAccess) array_expr;
275 CCodeExpression length_expr = null;
277 if (field.has_array_length_cexpr) {
278 length_expr = new CCodeConstant (field.get_array_length_cexpr ());
279 } else if (field.binding == MemberBinding.INSTANCE) {
280 var cl = field.parent_symbol as Class;
281 bool is_gtypeinstance = (cl != null && !cl.is_compact);
283 string length_cname;
284 if (field.has_array_length_cname) {
285 length_cname = field.get_array_length_cname ();
286 } else {
287 length_cname = get_array_length_cname (field.name, dim);
289 CCodeExpression typed_inst = (CCodeExpression) get_ccodenode (ma.inner);
291 CCodeExpression inst;
292 if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) {
293 inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
294 } else {
295 inst = typed_inst;
297 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
298 length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
299 } else {
300 length_expr = new CCodeMemberAccess (inst, length_cname);
302 } else {
303 length_expr = new CCodeIdentifier (get_array_length_cname (field.get_cname (), dim));
306 if (is_out) {
307 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
308 } else {
309 return length_expr;
312 } else if (array_expr.symbol_reference is Constant) {
313 var constant = (Constant) array_expr.symbol_reference;
314 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_N_ELEMENTS"));
315 ccall.add_argument (new CCodeIdentifier (constant.get_cname ()));
316 return ccall;
317 } else if (array_expr.symbol_reference is Property) {
318 var prop = (Property) array_expr.symbol_reference;
319 if (!prop.no_array_length) {
320 Gee.List<CCodeExpression> size = array_expr.get_array_sizes ();
321 if (size.size >= dim) {
322 return size[dim - 1];
326 } else if (array_expr is NullLiteral) {
327 return new CCodeConstant ("0");
330 if (!is_out) {
331 /* allow arrays with unknown length even for value types
332 * as else it may be impossible to bind some libraries
333 * users of affected libraries should explicitly set
334 * the array length as early as possible
335 * by setting the virtual length field of the array
337 return new CCodeConstant ("-1");
338 } else {
339 return new CCodeConstant ("NULL");
343 public override string get_array_size_cname (string array_cname) {
344 return "%s_size".printf (array_cname);
347 public override CCodeExpression get_array_size_cexpression (Expression array_expr) {
348 if (array_expr.symbol_reference is LocalVariable) {
349 var local = (LocalVariable) array_expr.symbol_reference;
350 return get_variable_cexpression (get_array_size_cname (get_variable_cname (local.name)));
351 } else if (array_expr.symbol_reference is Field) {
352 var field = (Field) array_expr.symbol_reference;
353 var ma = (MemberAccess) array_expr;
355 CCodeExpression size_expr = null;
357 if (field.binding == MemberBinding.INSTANCE) {
358 var cl = field.parent_symbol as Class;
359 bool is_gtypeinstance = (cl != null && !cl.is_compact);
361 string size_cname = get_array_size_cname (field.name);
362 CCodeExpression typed_inst = (CCodeExpression) get_ccodenode (ma.inner);
364 CCodeExpression inst;
365 if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) {
366 inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
367 } else {
368 inst = typed_inst;
370 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
371 size_expr = new CCodeMemberAccess.pointer (inst, size_cname);
372 } else {
373 size_expr = new CCodeMemberAccess (inst, size_cname);
375 } else {
376 size_expr = new CCodeIdentifier (get_array_size_cname (field.get_cname ()));
379 return size_expr;
382 assert_not_reached ();
385 public override void visit_element_access (ElementAccess expr) {
386 expr.accept_children (codegen);
388 Gee.List<Expression> indices = expr.get_indices ();
389 int rank = indices.size;
391 var container_type = expr.container.value_type.data_type;
393 var ccontainer = (CCodeExpression) expr.container.ccodenode;
394 var cindex = (CCodeExpression) indices[0].ccodenode;
395 if (expr.container.symbol_reference is ArrayLengthField) {
396 /* Figure if cindex is a constant expression and calculate dim...*/
397 var lit = indices[0] as IntegerLiteral;
398 var memberaccess = expr.container as MemberAccess;
399 if (lit != null && memberaccess != null) {
400 int dim = lit.value.to_int ();
401 expr.ccodenode = head.get_array_length_cexpression (memberaccess.inner, dim + 1);
403 } else if (container_type == string_type.data_type) {
404 // should be moved to a different module
406 // access to unichar in a string
407 var coffsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_utf8_offset_to_pointer"));
408 coffsetcall.add_argument (ccontainer);
409 coffsetcall.add_argument (cindex);
411 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_utf8_get_char"));
412 ccall.add_argument (coffsetcall);
414 expr.ccodenode = ccall;
415 } else {
416 // access to element in an array
417 for (int i = 1; i < rank; i++) {
418 var cmul = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, cindex, head.get_array_length_cexpression (expr.container, i + 1));
419 cindex = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, cmul, (CCodeExpression) indices[i].ccodenode);
421 expr.ccodenode = new CCodeElementAccess (ccontainer, cindex);
425 private CCodeForStatement get_struct_array_free_loop (Struct st) {
426 var cbody = new CCodeBlock ();
427 var cptrarray = new CCodeIdentifier ("array");
428 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
430 var cfreecall = new CCodeFunctionCall (get_destroy_func_expression (new StructValueType (st)));
431 cfreecall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cea));
433 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
434 cbody.add_statement (new CCodeExpressionStatement (cfreecall));
436 var cfor = new CCodeForStatement (cforcond, cbody);
437 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
438 cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))));
440 return cfor;
443 public override string? append_struct_array_free (Struct st) {
444 string cname = "_vala_%s_array_free".printf (st.get_cname ());;
446 if (source_declarations.add_declaration (cname)) {
447 return cname;
450 var fun = new CCodeFunction (cname, "void");
451 fun.modifiers = CCodeModifiers.STATIC;
452 fun.add_parameter (new CCodeFormalParameter ("array", "%s*".printf (st.get_cname ())));
453 fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
454 source_declarations.add_type_member_declaration (fun.copy ());
456 var cdofree = new CCodeBlock ();
458 var citdecl = new CCodeDeclaration ("int");
459 citdecl.add_declarator (new CCodeVariableDeclarator ("i"));
460 cdofree.add_statement (citdecl);
462 cdofree.add_statement (get_struct_array_free_loop (st));
464 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
465 var cif = new CCodeIfStatement (ccondarr, cdofree);
466 fun.block = new CCodeBlock ();
467 fun.block.add_statement (cif);
469 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
470 carrfree.add_argument (new CCodeIdentifier ("array"));
471 fun.block.add_statement (new CCodeExpressionStatement (carrfree));
473 source_type_member_definition.append (fun);
475 return cname;
478 private CCodeForStatement get_vala_array_free_loop () {
479 var cbody = new CCodeBlock ();
480 var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*");
481 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
483 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier ("destroy_func"));
484 cfreecall.add_argument (cea);
486 var cfreecond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
487 var cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
488 var cfreeblock = new CCodeBlock ();
489 cfreeblock.add_statement (new CCodeExpressionStatement (cfreecall));
490 cbody.add_statement (new CCodeIfStatement (cfreecond, cfreeblock));
492 var cfor = new CCodeForStatement (cforcond, cbody);
493 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
494 cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))));
496 return cfor;
499 public override void append_vala_array_free () {
500 // _vala_array_destroy only frees elements but not the array itself
502 var fun = new CCodeFunction ("_vala_array_destroy", "void");
503 fun.modifiers = CCodeModifiers.STATIC;
504 fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
505 fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
506 fun.add_parameter (new CCodeFormalParameter ("destroy_func", "GDestroyNotify"));
507 source_declarations.add_type_member_declaration (fun.copy ());
509 var cdofree = new CCodeBlock ();
511 var citdecl = new CCodeDeclaration ("int");
512 citdecl.add_declarator (new CCodeVariableDeclarator ("i"));
513 cdofree.add_statement (citdecl);
515 cdofree.add_statement (get_vala_array_free_loop ());
517 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
518 var ccondfunc = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("destroy_func"), new CCodeConstant ("NULL"));
519 var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccondarr, ccondfunc), cdofree);
520 fun.block = new CCodeBlock ();
521 fun.block.add_statement (cif);
523 source_type_member_definition.append (fun);
525 // _vala_array_free frees elements and array
527 fun = new CCodeFunction ("_vala_array_free", "void");
528 fun.modifiers = CCodeModifiers.STATIC;
529 fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
530 fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
531 fun.add_parameter (new CCodeFormalParameter ("destroy_func", "GDestroyNotify"));
532 source_declarations.add_type_member_declaration (fun.copy ());
534 // call _vala_array_destroy to free the array elements
535 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
536 ccall.add_argument (new CCodeIdentifier ("array"));
537 ccall.add_argument (new CCodeIdentifier ("array_length"));
538 ccall.add_argument (new CCodeIdentifier ("destroy_func"));
540 fun.block = new CCodeBlock ();
541 fun.block.add_statement (new CCodeExpressionStatement (ccall));
543 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
544 carrfree.add_argument (new CCodeIdentifier ("array"));
545 fun.block.add_statement (new CCodeExpressionStatement (carrfree));
547 source_type_member_definition.append (fun);
550 public override void append_vala_array_move () {
551 source_declarations.add_include ("string.h");
553 // assumes that overwritten array elements are null before invocation
554 // FIXME will leak memory if that's not the case
555 var fun = new CCodeFunction ("_vala_array_move", "void");
556 fun.modifiers = CCodeModifiers.STATIC;
557 fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
558 fun.add_parameter (new CCodeFormalParameter ("element_size", "gsize"));
559 fun.add_parameter (new CCodeFormalParameter ("src", "gint"));
560 fun.add_parameter (new CCodeFormalParameter ("dest", "gint"));
561 fun.add_parameter (new CCodeFormalParameter ("length", "gint"));
562 source_declarations.add_type_member_declaration (fun.copy ());
564 var array = new CCodeCastExpression (new CCodeIdentifier ("array"), "char*");
565 var element_size = new CCodeIdentifier ("element_size");
566 var length = new CCodeIdentifier ("length");
567 var src = new CCodeIdentifier ("src");
568 var dest = new CCodeIdentifier ("dest");
569 var src_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, src, element_size));
570 var dest_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest, element_size));
571 var dest_end_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dest, length), element_size));
573 fun.block = new CCodeBlock ();
575 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_memmove"));
576 ccall.add_argument (dest_address);
577 ccall.add_argument (src_address);
578 ccall.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
579 fun.block.add_statement (new CCodeExpressionStatement (ccall));
581 var czero1 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
582 czero1.add_argument (src_address);
583 czero1.add_argument (new CCodeConstant ("0"));
584 czero1.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, dest, src), element_size));
585 var czeroblock1 = new CCodeBlock ();
586 czeroblock1.add_statement (new CCodeExpressionStatement (czero1));
588 var czero2 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
589 czero2.add_argument (dest_end_address);
590 czero2.add_argument (new CCodeConstant ("0"));
591 czero2.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, src, dest), element_size));
592 var czeroblock2 = new CCodeBlock ();
593 czeroblock2.add_statement (new CCodeExpressionStatement (czero2));
595 fun.block.add_statement (new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest), czeroblock1, czeroblock2));
597 source_type_member_definition.append (fun);
600 public override void append_vala_array_length () {
601 var fun = new CCodeFunction ("_vala_array_length", "gint");
602 fun.modifiers = CCodeModifiers.STATIC;
603 fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
604 source_declarations.add_type_member_declaration (fun.copy ());
606 var block = new CCodeBlock ();
608 var len_decl = new CCodeDeclaration ("int");
609 len_decl.add_declarator (new CCodeVariableDeclarator ("length", new CCodeConstant ("0")));
610 block.add_statement (len_decl);
612 var non_null_block = new CCodeBlock ();
614 var while_body = new CCodeBlock ();
615 while_body.add_statement (new CCodeExpressionStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("length"))));
617 var array_element_check = new CCodeElementAccess (new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*"), new CCodeConstant ("length"));
618 non_null_block.add_statement (new CCodeWhileStatement (array_element_check, while_body));
620 // return 0 if the array is NULL
621 // avoids an extra NULL check on the caller side
622 var array_check = new CCodeIdentifier ("array");
623 block.add_statement (new CCodeIfStatement (array_check, non_null_block));
625 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("length")));
627 fun.block = block;
629 source_type_member_definition.append (fun);
632 public override CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
633 if (expression_type is ArrayType) {
634 var array_type = (ArrayType) expression_type;
636 if (!array_type.fixed_length) {
637 return base.get_ref_cexpression (expression_type, cexpr, expr, node);
640 var decl = get_temp_variable (expression_type, false, node);
641 temp_vars.insert (0, decl);
643 var ctemp = get_variable_cexpression (decl.name);
645 var copy_call = new CCodeFunctionCall (new CCodeIdentifier (generate_array_copy_wrapper (array_type)));
646 copy_call.add_argument (cexpr);
647 copy_call.add_argument (ctemp);
649 var ccomma = new CCodeCommaExpression ();
651 ccomma.append_expression (copy_call);
652 ccomma.append_expression (ctemp);
654 return ccomma;
655 } else {
656 return base.get_ref_cexpression (expression_type, cexpr, expr, node);
660 public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference, bool is_chainup) {
661 if (type is ArrayType) {
662 var array_type = (ArrayType) type;
663 // fixed length arrays use different code
664 // generated by overridden get_ref_cexpression method
665 assert (!array_type.fixed_length);
666 return new CCodeIdentifier (generate_array_dup_wrapper (array_type));
667 } else {
668 return base.get_dup_func_expression (type, source_reference, is_chainup);
672 public override CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression expr, bool is_macro_definition) {
673 if (type is ArrayType) {
674 var array_type = (ArrayType) type;
676 if (!array_type.fixed_length) {
677 return base.get_unref_expression (cvar, type, expr, is_macro_definition);
680 requires_array_free = true;
682 var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
684 ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
685 ccall.add_argument (cvar);
686 ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length)));
687 ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
689 return ccall;
690 } else {
691 return base.get_unref_expression (cvar, type, expr, is_macro_definition);
695 string generate_array_dup_wrapper (ArrayType array_type) {
696 string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
698 if (!add_wrapper (dup_func)) {
699 // wrapper already defined
700 return dup_func;
703 // declaration
705 var function = new CCodeFunction (dup_func, array_type.get_cname ());
706 function.modifiers = CCodeModifiers.STATIC;
708 function.add_parameter (new CCodeFormalParameter ("self", array_type.get_cname ()));
709 // total length over all dimensions
710 function.add_parameter (new CCodeFormalParameter ("length", "int"));
712 // definition
714 var block = new CCodeBlock ();
716 if (requires_copy (array_type.element_type)) {
717 var old_symbol = current_symbol;
718 var old_temp_vars = temp_vars;
719 current_symbol = null;
721 var cdecl = new CCodeDeclaration (array_type.get_cname ());
722 var cvardecl = new CCodeVariableDeclarator ("result");
723 cdecl.add_declarator (cvardecl);
724 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
725 gnew.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
726 gnew.add_argument (new CCodeIdentifier ("length"));
727 cvardecl.initializer = gnew;
728 block.add_statement (cdecl);
730 var idx_decl = new CCodeDeclaration ("int");
731 idx_decl.add_declarator (new CCodeVariableDeclarator ("i"));
732 block.add_statement (idx_decl);
734 var loop_body = new CCodeBlock ();
735 loop_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("result"), new CCodeIdentifier ("i")), get_ref_cexpression (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), null, array_type))));
737 var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")), loop_body);
738 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
739 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
740 block.add_statement (cfor);
742 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
744 var cfrag = new CCodeFragment ();
745 append_temp_decl (cfrag, temp_vars);
746 block.add_statement (cfrag);
747 current_symbol = old_symbol;
748 temp_vars = old_temp_vars;
749 } else {
750 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
751 dup_call.add_argument (new CCodeIdentifier ("self"));
753 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
754 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
755 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("length"), sizeof_call));
757 block.add_statement (new CCodeReturnStatement (dup_call));
760 // append to file
762 source_declarations.add_type_member_declaration (function.copy ());
764 function.block = block;
765 source_type_member_definition.append (function);
767 return dup_func;
770 string generate_array_copy_wrapper (ArrayType array_type) {
771 string dup_func = "_vala_array_copy%d".printf (++next_array_dup_id);
773 if (!add_wrapper (dup_func)) {
774 // wrapper already defined
775 return dup_func;
778 // declaration
780 var function = new CCodeFunction (dup_func, "void");
781 function.modifiers = CCodeModifiers.STATIC;
783 function.add_parameter (new CCodeFormalParameter ("self", array_type.get_cname () + "*"));
784 function.add_parameter (new CCodeFormalParameter ("dest", array_type.get_cname () + "*"));
786 // definition
788 var block = new CCodeBlock ();
790 if (requires_copy (array_type.element_type)) {
791 var old_symbol = current_symbol;
792 var old_temp_vars = temp_vars;
793 current_symbol = null;
795 var idx_decl = new CCodeDeclaration ("int");
796 idx_decl.add_declarator (new CCodeVariableDeclarator ("i"));
797 block.add_statement (idx_decl);
799 var loop_body = new CCodeBlock ();
800 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))));
802 var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeConstant ("%d".printf (array_type.length))), loop_body);
803 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
804 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
805 block.add_statement (cfor);
807 var cfrag = new CCodeFragment ();
808 append_temp_decl (cfrag, temp_vars);
809 block.add_statement (cfrag);
810 current_symbol = old_symbol;
811 temp_vars = old_temp_vars;
812 } else {
813 source_declarations.add_include ("string.h");
815 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
816 dup_call.add_argument (new CCodeIdentifier ("dest"));
817 dup_call.add_argument (new CCodeIdentifier ("self"));
819 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
820 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
821 dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("%d".printf (array_type.length)), sizeof_call));
823 block.add_statement (new CCodeExpressionStatement (dup_call));
826 // append to file
828 source_declarations.add_type_member_declaration (function.copy ());
830 function.block = block;
831 source_type_member_definition.append (function);
833 return dup_func;
836 string generate_array_add_wrapper (ArrayType array_type) {
837 string add_func = "_vala_array_add%d".printf (++next_array_add_id);
839 if (!add_wrapper (add_func)) {
840 // wrapper already defined
841 return add_func;
844 // declaration
846 var function = new CCodeFunction (add_func, "void");
847 function.modifiers = CCodeModifiers.STATIC;
849 function.add_parameter (new CCodeFormalParameter ("array", array_type.get_cname () + "*"));
850 function.add_parameter (new CCodeFormalParameter ("length", "int*"));
851 function.add_parameter (new CCodeFormalParameter ("size", "int*"));
853 string typename = array_type.element_type.get_cname ();
854 CCodeExpression value = new CCodeIdentifier ("value");
855 if (array_type.element_type.is_real_struct_type ()) {
856 if (!array_type.element_type.nullable || !array_type.element_type.value_owned) {
857 typename = "const " + typename;
859 if (!array_type.element_type.nullable) {
860 typename += "*";
861 value = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, value);
864 function.add_parameter (new CCodeFormalParameter ("value", typename));
866 var array = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("array"));
867 var length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("length"));
868 var size = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("size"));
870 // definition
872 var block = new CCodeBlock ();
874 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
875 renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
876 renew_call.add_argument (array);
877 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
878 // NULL terminate array
879 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, size, new CCodeConstant ("1")));
880 } else {
881 renew_call.add_argument (size);
884 var resize_block = new CCodeBlock ();
885 resize_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (size, new CCodeConditionalExpression (size, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), size), new CCodeConstant ("4")))));
886 resize_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (array, renew_call)));
888 var csizecheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, length, size);
889 block.add_statement (new CCodeIfStatement (csizecheck, resize_block));
891 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (array, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value)));
893 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
894 // NULL terminate array
895 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (array, length), new CCodeConstant ("NULL"))));
898 // append to file
900 source_declarations.add_type_member_declaration (function.copy ());
902 function.block = block;
903 source_type_member_definition.append (function);
905 return add_func;
908 bool is_array_add (Assignment assignment) {
909 var binary = assignment.right as BinaryExpression;
910 if (binary != null && binary.left.value_type is ArrayType) {
911 if (binary.operator == BinaryOperator.PLUS) {
912 if (assignment.left.symbol_reference == binary.left.symbol_reference) {
913 return true;
918 return false;
921 public override void visit_assignment (Assignment assignment) {
922 if (!is_array_add (assignment)) {
923 base.visit_assignment (assignment);
924 return;
927 var binary = assignment.right as BinaryExpression;
929 var array = binary.left;
930 var array_type = (ArrayType) array.value_type;
931 var element = binary.right;
933 array.accept (codegen);
934 element.target_type = array_type.element_type.copy ();
935 element.accept (codegen);
937 var value_param = new FormalParameter ("value", element.target_type);
939 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (array_type)));
940 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) array.ccodenode));
941 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cexpression (array)));
942 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_size_cexpression (array)));
943 ccall.add_argument (handle_struct_argument (value_param, element, (CCodeExpression) element.ccodenode));
945 assignment.ccodenode = ccall;
948 public override void generate_parameter (FormalParameter param, CCodeDeclarationSpace decl_space, Map<int,CCodeFormalParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
949 if (!(param.parameter_type is ArrayType)) {
950 base.generate_parameter (param, decl_space, cparam_map, carg_map);
951 return;
954 string ctypename = param.parameter_type.get_cname ();
956 if (param.direction != ParameterDirection.IN) {
957 ctypename += "*";
960 param.ccodenode = new CCodeFormalParameter (get_variable_cname (param.name), ctypename);
962 var array_type = (ArrayType) param.parameter_type;
964 generate_type_declaration (array_type.element_type, decl_space);
966 cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
967 if (carg_map != null) {
968 carg_map.set (get_param_pos (param.cparameter_position), get_variable_cexpression (param.name));
971 if (!param.no_array_length) {
972 var length_ctype = "int";
973 if (param.direction != ParameterDirection.IN) {
974 length_ctype = "int*";
977 for (int dim = 1; dim <= array_type.rank; dim++) {
978 var cparam = new CCodeFormalParameter (head.get_array_length_cname (get_variable_cname (param.name), dim), length_ctype);
979 cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
980 if (carg_map != null) {
981 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), get_variable_cexpression (cparam.name));