1 /* valaccodearraymodule.vala
3 * Copyright (C) 2006-2010 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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 public class Vala
.CCodeArrayModule
: CCodeMethodCallModule
{
27 int next_array_dup_id
= 0;
28 int next_array_add_id
= 0;
30 void append_initializer_list (CCodeExpression name_cnode
, InitializerList initializer_list
, int rank
, ref int i
) {
31 foreach (Expression e
in initializer_list
.get_initializers ()) {
33 append_initializer_list (name_cnode
, (InitializerList
) e
, rank
- 1, ref i
);
35 ccode
.add_assignment (new
CCodeElementAccess (name_cnode
, new
CCodeConstant (i
.to_string ())), get_cvalue (e
));
41 public override void visit_array_creation_expression (ArrayCreationExpression expr
) {
42 var array_type
= expr
.target_type as ArrayType
;
43 if (array_type
!= null && array_type
.fixed_length
) {
44 // no heap allocation for fixed-length arrays
46 var temp_var
= get_temp_variable (array_type
, true, expr
);
47 var name_cnode
= get_variable_cexpression (temp_var
.name
);
50 emit_temp_var (temp_var
);
52 append_initializer_list (name_cnode
, expr
.initializer_list
, expr
.rank
, ref i
);
54 set_cvalue (expr
, name_cnode
);
59 CCodeFunctionCall gnew
;
60 if (context
.profile
== Profile
.POSIX
) {
61 cfile
.add_include ("stdlib.h");
62 gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("calloc"));
64 gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
65 gnew
.add_argument (new
CCodeIdentifier (expr
.element_type
.get_cname ()));
69 CCodeExpression cexpr
= null;
71 // iterate over each dimension
72 foreach (Expression size
in expr
.get_sizes ()) {
73 CCodeExpression csize
= get_cvalue (size
);
75 if (!is_pure_ccode_expression (csize
)) {
76 var temp_var
= get_temp_variable (int_type
, false, expr
);
77 var name_cnode
= get_variable_cexpression (temp_var
.name
);
78 set_cvalue (size
, name_cnode
);
80 emit_temp_var (temp_var
);
82 csize
= new
CCodeAssignment (name_cnode
, csize
);
84 append_array_length (expr
, name_cnode
);
86 append_array_length (expr
, csize
);
93 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cexpr
, csize
);
97 // add extra item to have array NULL-terminated for all reference types
98 if (expr
.element_type
.data_type
!= null && expr
.element_type
.data_type
.is_reference_type ()) {
99 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cexpr
, new
CCodeConstant ("1"));
102 gnew
.add_argument (cexpr
);
104 if (context
.profile
== Profile
.POSIX
) {
105 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
106 csizeof
.add_argument (new
CCodeIdentifier (expr
.element_type
.get_cname ()));
107 gnew
.add_argument (csizeof
);
110 var temp_var
= get_temp_variable (expr
.value_type
, true, expr
);
111 var name_cnode
= get_variable_cexpression (temp_var
.name
);
114 emit_temp_var (temp_var
);
116 ccode
.add_assignment (name_cnode
, gnew
);
118 if (expr
.initializer_list
!= null) {
119 append_initializer_list (name_cnode
, expr
.initializer_list
, expr
.rank
, ref i
);
122 set_cvalue (expr
, name_cnode
);
125 public override string get_array_length_cname (string array_cname
, int dim
) {
126 return "%s_length%d".printf (array_cname
, dim
);
129 public override string get_parameter_array_length_cname (Parameter param
, int dim
) {
130 if (param
.has_array_length_cname
) {
131 return param
.get_array_length_cname ();
133 return get_array_length_cname (get_variable_cname (param
.name
), dim
);
137 public override CCodeExpression
get_array_length_cexpression (Expression array_expr
, int dim
= -1) {
138 return get_array_length_cvalue (array_expr
.target_value
, dim
);
141 public override CCodeExpression
get_array_length_cvalue (TargetValue value
, int dim
= -1) {
142 var array_type
= value
.value_type as ArrayType
;
144 if (array_type
!= null && array_type
.fixed_length
) {
145 return new
CCodeConstant (array_type
.length
.to_string ());
148 // dim == -1 => total size over all dimensions
150 if (array_type
!= null && array_type
.rank
> 1) {
151 CCodeExpression cexpr
= get_array_length_cvalue (value
, 1);
152 for (dim
= 2; dim
<= array_type
.rank
; dim
++) {
153 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cexpr
, get_array_length_cvalue (value
, dim
));
161 List
<CCodeExpression
> size
= ((GLibValue
) value
).array_length_cvalues
;
162 assert (size
!= null && size
.size
>= dim
);
163 return size
[dim
- 1];
166 public override string get_array_size_cname (string array_cname
) {
167 return "_%s_size_".printf (array_cname
);
170 public override void visit_element_access (ElementAccess expr
) {
171 List
<Expression
> indices
= expr
.get_indices ();
172 int rank
= indices
.size
;
174 var ccontainer
= get_cvalue (expr
.container
);
175 var cindex
= get_cvalue (indices
[0]);
176 if (expr
.container
.symbol_reference is ArrayLengthField
) {
177 /* Figure if cindex is a constant expression and calculate dim...*/
178 var lit
= indices
[0] as IntegerLiteral
;
179 var memberaccess
= expr
.container as MemberAccess
;
180 if (lit
!= null && memberaccess
!= null) {
181 int dim
= int.parse (lit
.value
);
182 set_cvalue (expr
, get_array_length_cexpression (memberaccess
.inner
, dim
+ 1));
184 Report
.error (expr
.source_reference
, "only integer literals supported as index");
187 // access to element in an array
188 for (int i
= 1; i
< rank
; i
++) {
189 var cmul
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cindex
, get_array_length_cexpression (expr
.container
, i
+ 1));
190 cindex
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cmul
, get_cvalue (indices
[i
]));
192 set_cvalue (expr
, new
CCodeElementAccess (ccontainer
, cindex
));
196 public override void visit_slice_expression (SliceExpression expr
) {
197 var ccontainer
= get_cvalue (expr
.container
);
198 var cstart
= get_cvalue (expr
.start
);
199 var cstop
= get_cvalue (expr
.stop
);
201 var cstartpointer
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, ccontainer
, cstart
);
202 var splicelen
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, cstop
, cstart
);
204 set_cvalue (expr
, cstartpointer
);
205 append_array_length (expr
, splicelen
);
208 void append_struct_array_free_loop (Struct st
) {
209 var cforinit
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
210 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("array_length"));
211 var cforiter
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("i"), new
CCodeConstant ("1")));
212 ccode
.open_for (cforinit
, cforcond
, cforiter
);
214 var cptrarray
= new
CCodeIdentifier ("array");
215 var cea
= new
CCodeElementAccess (cptrarray
, new
CCodeIdentifier ("i"));
217 var cfreecall
= new
CCodeFunctionCall (get_destroy_func_expression (new
StructValueType (st
)));
218 cfreecall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cea
));
219 ccode
.add_expression (cfreecall
);
224 public override string?
append_struct_array_free (Struct st
) {
225 string cname
= "_vala_%s_array_free".printf (st
.get_cname ());;
227 if (cfile
.add_declaration (cname
)) {
231 var fun
= new
CCodeFunction (cname
, "void");
232 fun
.modifiers
= CCodeModifiers
.STATIC
;
233 fun
.add_parameter (new
CCodeParameter ("array", "%s*".printf (st
.get_cname ())));
234 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
238 var ccondarr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("array"), new
CCodeConstant ("NULL"));
239 ccode
.open_if (ccondarr
);
241 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
242 append_struct_array_free_loop (st
);
246 var carrfree
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
247 carrfree
.add_argument (new
CCodeIdentifier ("array"));
248 ccode
.add_expression (carrfree
);
252 cfile
.add_function_declaration (fun
);
253 cfile
.add_function (fun
);
258 void append_vala_array_free_loop () {
259 var cforinit
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
260 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("array_length"));
261 var cforiter
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("i"), new
CCodeConstant ("1")));
262 ccode
.open_for (cforinit
, cforcond
, cforiter
);
264 var cptrarray
= new
CCodeCastExpression (new
CCodeIdentifier ("array"), "gpointer*");
265 var cea
= new
CCodeElementAccess (cptrarray
, new
CCodeIdentifier ("i"));
267 var cfreecond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, cea
, new
CCodeConstant ("NULL"));
268 ccode
.open_if (cfreecond
);
270 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("destroy_func"));
271 cfreecall
.add_argument (cea
);
272 ccode
.add_expression (cfreecall
);
277 public override void append_vala_array_free () {
278 // _vala_array_destroy only frees elements but not the array itself
280 var fun
= new
CCodeFunction ("_vala_array_destroy", "void");
281 fun
.modifiers
= CCodeModifiers
.STATIC
;
282 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
283 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
284 fun
.add_parameter (new
CCodeParameter ("destroy_func", "GDestroyNotify"));
288 var ccondarr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("array"), new
CCodeConstant ("NULL"));
289 var ccondfunc
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("destroy_func"), new
CCodeConstant ("NULL"));
290 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, ccondarr
, ccondfunc
));
292 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
293 append_vala_array_free_loop ();
299 cfile
.add_function_declaration (fun
);
300 cfile
.add_function (fun
);
302 // _vala_array_free frees elements and array
304 fun
= new
CCodeFunction ("_vala_array_free", "void");
305 fun
.modifiers
= CCodeModifiers
.STATIC
;
306 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
307 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
308 fun
.add_parameter (new
CCodeParameter ("destroy_func", "GDestroyNotify"));
312 // call _vala_array_destroy to free the array elements
313 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
314 ccall
.add_argument (new
CCodeIdentifier ("array"));
315 ccall
.add_argument (new
CCodeIdentifier ("array_length"));
316 ccall
.add_argument (new
CCodeIdentifier ("destroy_func"));
317 ccode
.add_expression (ccall
);
319 var carrfree
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
320 carrfree
.add_argument (new
CCodeIdentifier ("array"));
321 ccode
.add_expression (carrfree
);
325 cfile
.add_function_declaration (fun
);
326 cfile
.add_function (fun
);
329 public override void append_vala_array_move () {
330 cfile
.add_include ("string.h");
332 // assumes that overwritten array elements are null before invocation
333 // FIXME will leak memory if that's not the case
334 var fun
= new
CCodeFunction ("_vala_array_move", "void");
335 fun
.modifiers
= CCodeModifiers
.STATIC
;
336 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
337 fun
.add_parameter (new
CCodeParameter ("element_size", "gsize"));
338 fun
.add_parameter (new
CCodeParameter ("src", "gint"));
339 fun
.add_parameter (new
CCodeParameter ("dest", "gint"));
340 fun
.add_parameter (new
CCodeParameter ("length", "gint"));
344 var array
= new
CCodeCastExpression (new
CCodeIdentifier ("array"), "char*");
345 var element_size
= new
CCodeIdentifier ("element_size");
346 var length
= new
CCodeIdentifier ("length");
347 var src
= new
CCodeIdentifier ("src");
348 var dest
= new
CCodeIdentifier ("dest");
349 var src_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, src
, element_size
));
350 var dest_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, dest
, element_size
));
351 var dest_end_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, dest
, length
), element_size
));
353 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memmove"));
354 ccall
.add_argument (dest_address
);
355 ccall
.add_argument (src_address
);
356 ccall
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, length
, element_size
));
357 ccode
.add_expression (ccall
);
359 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, src
, dest
));
361 var czero1
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
362 czero1
.add_argument (src_address
);
363 czero1
.add_argument (new
CCodeConstant ("0"));
364 czero1
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, dest
, src
), element_size
));
365 ccode
.add_expression (czero1
);
369 var czero2
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
370 czero2
.add_argument (dest_end_address
);
371 czero2
.add_argument (new
CCodeConstant ("0"));
372 czero2
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, src
, dest
), element_size
));
373 ccode
.add_expression (czero2
);
379 cfile
.add_function_declaration (fun
);
380 cfile
.add_function (fun
);
383 public override void append_vala_array_length () {
384 var fun
= new
CCodeFunction ("_vala_array_length", "gint");
385 fun
.modifiers
= CCodeModifiers
.STATIC
;
386 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
390 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("length", new
CCodeConstant ("0")));
392 // return 0 if the array is NULL
393 // avoids an extra NULL check on the caller side
394 var array_check
= new
CCodeIdentifier ("array");
395 ccode
.open_if (array_check
);
397 var array_element_check
= new
CCodeElementAccess (new
CCodeCastExpression (new
CCodeIdentifier ("array"), "gpointer*"), new
CCodeConstant ("length"));
398 ccode
.open_while (array_element_check
);
399 ccode
.add_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("length")));
404 ccode
.add_return (new
CCodeIdentifier ("length"));
408 cfile
.add_function_declaration (fun
);
409 cfile
.add_function (fun
);
412 public override CCodeExpression?
get_ref_cexpression (DataType expression_type
, CCodeExpression cexpr
, Expression? expr
, CodeNode node
) {
413 if (expression_type is ArrayType
) {
414 var array_type
= (ArrayType
) expression_type
;
416 if (!array_type
.fixed_length
) {
417 return base.get_ref_cexpression (expression_type
, cexpr
, expr
, node
);
420 var decl
= get_temp_variable (expression_type
, false, node
);
421 emit_temp_var (decl
);
423 var ctemp
= get_variable_cexpression (decl
.name
);
425 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_copy_wrapper (array_type
)));
426 copy_call
.add_argument (cexpr
);
427 copy_call
.add_argument (ctemp
);
429 var ccomma
= new
CCodeCommaExpression ();
431 ccomma
.append_expression (copy_call
);
432 ccomma
.append_expression (ctemp
);
436 return base.get_ref_cexpression (expression_type
, cexpr
, expr
, node
);
440 public override CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
) {
441 if (type is ArrayType
) {
442 var array_type
= (ArrayType
) type
;
443 // fixed length arrays use different code
444 // generated by overridden get_ref_cexpression method
445 assert (!array_type
.fixed_length
);
446 return new
CCodeIdentifier (generate_array_dup_wrapper (array_type
));
448 return base.get_dup_func_expression (type
, source_reference
, is_chainup
);
452 public override CCodeExpression
destroy_variable (Variable variable
, CCodeExpression? inner
= null) {
453 var array_type
= variable
.variable_type as ArrayType
;
454 if (array_type
!= null && array_type
.fixed_length
) {
455 requires_array_free
= true;
457 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (variable
.variable_type
));
458 var value
= get_variable_cvalue (variable
);
460 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
461 ccall
.add_argument (get_cvalue_ (value
));
462 ccall
.add_argument (new
CCodeConstant ("%d".printf (array_type
.length
)));
463 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
468 return base.destroy_variable (variable
, inner
);
471 public override CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
472 var type
= value
.value_type
;
474 if (type is ArrayType
) {
475 var array_type
= (ArrayType
) type
;
477 if (!array_type
.fixed_length
) {
478 return base.destroy_value (value
, is_macro_definition
);
481 requires_array_free
= true;
483 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
485 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
486 ccall
.add_argument (get_cvalue_ (value
));
487 ccall
.add_argument (new
CCodeConstant ("%d".printf (array_type
.length
)));
488 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
492 return base.destroy_value (value
, is_macro_definition
);
496 string generate_array_dup_wrapper (ArrayType array_type
) {
497 string dup_func
= "_vala_array_dup%d".printf (++next_array_dup_id
);
499 if (!add_wrapper (dup_func
)) {
500 // wrapper already defined
506 var function
= new
CCodeFunction (dup_func
, array_type
.get_cname ());
507 function
.modifiers
= CCodeModifiers
.STATIC
;
509 function
.add_parameter (new
CCodeParameter ("self", array_type
.get_cname ()));
510 // total length over all dimensions
511 function
.add_parameter (new
CCodeParameter ("length", "int"));
512 if (array_type
.element_type is GenericType
) {
513 // dup function array elements
514 string func_name
= "%s_dup_func".printf (array_type
.element_type
.type_parameter
.name
.down ());
515 function
.add_parameter (new
CCodeParameter (func_name
, "GBoxedCopyFunc"));
520 push_context (new
EmitContext ());
521 push_function (function
);
523 if (requires_copy (array_type
.element_type
)) {
524 var cvardecl
= new
CCodeVariableDeclarator ("result");
525 var gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
526 gnew
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
528 CCodeExpression length_expr
= new
CCodeIdentifier ("length");
529 // add extra item to have array NULL-terminated for all reference types
530 if (array_type
.element_type
.data_type
!= null && array_type
.element_type
.data_type
.is_reference_type ()) {
531 length_expr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, length_expr
, new
CCodeConstant ("1"));
533 gnew
.add_argument (length_expr
);
535 ccode
.add_declaration (array_type
.get_cname (), cvardecl
);
536 ccode
.add_assignment (new
CCodeIdentifier ("result"), gnew
);
538 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
540 ccode
.open_for (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")),
541 new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("length")),
542 new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
544 ccode
.add_assignment (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
));
547 ccode
.add_return (new
CCodeIdentifier ("result"));
549 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memdup"));
550 dup_call
.add_argument (new
CCodeIdentifier ("self"));
552 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
553 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
554 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeIdentifier ("length"), sizeof_call
));
556 ccode
.add_return (dup_call
);
561 cfile
.add_function_declaration (function
);
562 cfile
.add_function (function
);
569 string generate_array_copy_wrapper (ArrayType array_type
) {
570 string dup_func
= "_vala_array_copy%d".printf (++next_array_dup_id
);
572 if (!add_wrapper (dup_func
)) {
573 // wrapper already defined
579 var function
= new
CCodeFunction (dup_func
, "void");
580 function
.modifiers
= CCodeModifiers
.STATIC
;
582 function
.add_parameter (new
CCodeParameter ("self", array_type
.get_cname () + "*"));
583 function
.add_parameter (new
CCodeParameter ("dest", array_type
.get_cname () + "*"));
587 push_context (new
EmitContext ());
588 push_function (function
);
590 if (requires_copy (array_type
.element_type
)) {
591 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
593 ccode
.open_for (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")),
594 new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeConstant ("%d".printf (array_type
.length
))),
595 new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
598 ccode
.add_assignment (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
));
600 cfile
.add_include ("string.h");
602 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
603 dup_call
.add_argument (new
CCodeIdentifier ("dest"));
604 dup_call
.add_argument (new
CCodeIdentifier ("self"));
606 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
607 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
608 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
));
610 ccode
.add_expression (dup_call
);
615 cfile
.add_function_declaration (function
);
616 cfile
.add_function (function
);
623 string generate_array_add_wrapper (ArrayType array_type
) {
624 string add_func
= "_vala_array_add%d".printf (++next_array_add_id
);
626 if (!add_wrapper (add_func
)) {
627 // wrapper already defined
631 var function
= new
CCodeFunction (add_func
, "void");
632 function
.modifiers
= CCodeModifiers
.STATIC
;
634 function
.add_parameter (new
CCodeParameter ("array", array_type
.get_cname () + "*"));
635 function
.add_parameter (new
CCodeParameter ("length", "int*"));
636 function
.add_parameter (new
CCodeParameter ("size", "int*"));
638 push_function (function
);
640 string typename
= array_type
.element_type
.get_cname ();
641 CCodeExpression value
= new
CCodeIdentifier ("value");
642 if (array_type
.element_type
.is_real_struct_type ()) {
643 if (!array_type
.element_type
.nullable
|| !array_type
.element_type
.value_owned
) {
644 typename
= "const " + typename
;
646 if (!array_type
.element_type
.nullable
) {
648 value
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, value
);
651 function
.add_parameter (new
CCodeParameter ("value", typename
));
653 var array
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("array"));
654 var length
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("length"));
655 var size
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("size"));
657 var renew_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_renew"));
658 renew_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
659 renew_call
.add_argument (array
);
660 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
661 // NULL terminate array
662 renew_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, size
, new
CCodeConstant ("1")));
664 renew_call
.add_argument (size
);
667 var csizecheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, length
, size
);
668 ccode
.open_if (csizecheck
);
669 ccode
.add_assignment (size
, new
CCodeConditionalExpression (size
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("2"), size
), new
CCodeConstant ("4")));
670 ccode
.add_assignment (array
, renew_call
);
673 ccode
.add_assignment (new
CCodeElementAccess (array
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, length
)), value
);
675 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
676 // NULL terminate array
677 ccode
.add_assignment (new
CCodeElementAccess (array
, length
), new
CCodeConstant ("NULL"));
682 cfile
.add_function_declaration (function
);
683 cfile
.add_function (function
);
688 bool is_array_add (Assignment assignment
) {
689 var binary
= assignment
.right as BinaryExpression
;
690 if (binary
!= null && binary
.left
.value_type is ArrayType
) {
691 if (binary
.operator
== BinaryOperator
.PLUS
) {
692 if (assignment
.left
.symbol_reference
== binary
.left
.symbol_reference
) {
701 public override void visit_assignment (Assignment assignment
) {
702 if (!is_array_add (assignment
)) {
703 base.visit_assignment (assignment
);
707 var binary
= (BinaryExpression
) assignment
.right
;
709 var array
= binary
.left
;
710 var array_type
= (ArrayType
) array
.value_type
;
711 var element
= binary
.right
;
713 var array_var
= assignment
.left
.symbol_reference
;
714 if (array_type
.rank
== 1 && array_var
!= null && array_var
.is_internal_symbol ()
715 && (array_var is LocalVariable
|| array_var is Field
)) {
718 Report
.error (assignment
.source_reference
, "Array concatenation not supported for public array variables and parameters");
722 var value_param
= new
Parameter ("value", element
.target_type
);
724 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_add_wrapper (array_type
)));
725 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (array
)));
726 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cexpression (array
)));
727 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_size_cvalue (array
.target_value
)));
728 ccall
.add_argument (handle_struct_argument (value_param
, element
, get_cvalue (element
)));
730 ccode
.add_expression (ccall
);
733 public override CCodeParameter
generate_parameter (Parameter param
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
734 if (!(param
.variable_type is ArrayType
)) {
735 return base.generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
738 string ctypename
= param
.variable_type
.get_cname ();
740 if (param
.direction
!= ParameterDirection
.IN
) {
744 var main_cparam
= new
CCodeParameter (get_variable_cname (param
.name
), ctypename
);
746 var array_type
= (ArrayType
) param
.variable_type
;
748 generate_type_declaration (array_type
.element_type
, decl_space
);
750 cparam_map
.set (get_param_pos (param
.cparameter_position
), main_cparam
);
751 if (carg_map
!= null) {
752 carg_map
.set (get_param_pos (param
.cparameter_position
), get_variable_cexpression (param
.name
));
755 if (!param
.no_array_length
) {
756 string length_ctype
= "int";
757 if (param
.array_length_type
!= null) {
758 length_ctype
= param
.array_length_type
;
760 if (param
.direction
!= ParameterDirection
.IN
) {
761 length_ctype
= "%s*".printf (length_ctype
);
764 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
765 var cparam
= new
CCodeParameter (get_parameter_array_length_cname (param
, dim
), length_ctype
);
766 cparam_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
767 if (carg_map
!= null) {
768 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), get_variable_cexpression (cparam
.name
));