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
, TargetValue value
) {
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
));
459 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
460 ccall
.add_argument (get_cvalue_ (value
));
461 ccall
.add_argument (new
CCodeConstant ("%d".printf (array_type
.length
)));
462 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
467 return base.destroy_variable (variable
, value
);
470 public override CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
471 var type
= value
.value_type
;
473 if (type is ArrayType
) {
474 var array_type
= (ArrayType
) type
;
476 if (!array_type
.fixed_length
) {
477 return base.destroy_value (value
, is_macro_definition
);
480 requires_array_free
= true;
482 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
484 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
485 ccall
.add_argument (get_cvalue_ (value
));
486 ccall
.add_argument (new
CCodeConstant ("%d".printf (array_type
.length
)));
487 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
491 return base.destroy_value (value
, is_macro_definition
);
495 string generate_array_dup_wrapper (ArrayType array_type
) {
496 string dup_func
= "_vala_array_dup%d".printf (++next_array_dup_id
);
498 if (!add_wrapper (dup_func
)) {
499 // wrapper already defined
505 var function
= new
CCodeFunction (dup_func
, array_type
.get_cname ());
506 function
.modifiers
= CCodeModifiers
.STATIC
;
508 function
.add_parameter (new
CCodeParameter ("self", array_type
.get_cname ()));
509 // total length over all dimensions
510 function
.add_parameter (new
CCodeParameter ("length", "int"));
511 if (array_type
.element_type is GenericType
) {
512 // dup function array elements
513 string func_name
= "%s_dup_func".printf (array_type
.element_type
.type_parameter
.name
.down ());
514 function
.add_parameter (new
CCodeParameter (func_name
, "GBoxedCopyFunc"));
519 push_context (new
EmitContext ());
520 push_function (function
);
522 if (requires_copy (array_type
.element_type
)) {
523 var cvardecl
= new
CCodeVariableDeclarator ("result");
524 var gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
525 gnew
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
527 CCodeExpression length_expr
= new
CCodeIdentifier ("length");
528 // add extra item to have array NULL-terminated for all reference types
529 if (array_type
.element_type
.data_type
!= null && array_type
.element_type
.data_type
.is_reference_type ()) {
530 length_expr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, length_expr
, new
CCodeConstant ("1"));
532 gnew
.add_argument (length_expr
);
534 ccode
.add_declaration (array_type
.get_cname (), cvardecl
);
535 ccode
.add_assignment (new
CCodeIdentifier ("result"), gnew
);
537 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
539 ccode
.open_for (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")),
540 new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("length")),
541 new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
543 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
));
546 ccode
.add_return (new
CCodeIdentifier ("result"));
548 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memdup"));
549 dup_call
.add_argument (new
CCodeIdentifier ("self"));
551 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
552 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
553 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeIdentifier ("length"), sizeof_call
));
555 ccode
.add_return (dup_call
);
560 cfile
.add_function_declaration (function
);
561 cfile
.add_function (function
);
568 string generate_array_copy_wrapper (ArrayType array_type
) {
569 string dup_func
= "_vala_array_copy%d".printf (++next_array_dup_id
);
571 if (!add_wrapper (dup_func
)) {
572 // wrapper already defined
578 var function
= new
CCodeFunction (dup_func
, "void");
579 function
.modifiers
= CCodeModifiers
.STATIC
;
581 function
.add_parameter (new
CCodeParameter ("self", array_type
.get_cname () + "*"));
582 function
.add_parameter (new
CCodeParameter ("dest", array_type
.get_cname () + "*"));
586 push_context (new
EmitContext ());
587 push_function (function
);
589 if (requires_copy (array_type
.element_type
)) {
590 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
592 ccode
.open_for (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")),
593 new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeConstant ("%d".printf (array_type
.length
))),
594 new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
597 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
));
599 cfile
.add_include ("string.h");
601 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
602 dup_call
.add_argument (new
CCodeIdentifier ("dest"));
603 dup_call
.add_argument (new
CCodeIdentifier ("self"));
605 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
606 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
607 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
));
609 ccode
.add_expression (dup_call
);
614 cfile
.add_function_declaration (function
);
615 cfile
.add_function (function
);
622 string generate_array_add_wrapper (ArrayType array_type
) {
623 string add_func
= "_vala_array_add%d".printf (++next_array_add_id
);
625 if (!add_wrapper (add_func
)) {
626 // wrapper already defined
630 var function
= new
CCodeFunction (add_func
, "void");
631 function
.modifiers
= CCodeModifiers
.STATIC
;
633 function
.add_parameter (new
CCodeParameter ("array", array_type
.get_cname () + "*"));
634 function
.add_parameter (new
CCodeParameter ("length", "int*"));
635 function
.add_parameter (new
CCodeParameter ("size", "int*"));
637 push_function (function
);
639 string typename
= array_type
.element_type
.get_cname ();
640 CCodeExpression value
= new
CCodeIdentifier ("value");
641 if (array_type
.element_type
.is_real_struct_type ()) {
642 if (!array_type
.element_type
.nullable
|| !array_type
.element_type
.value_owned
) {
643 typename
= "const " + typename
;
645 if (!array_type
.element_type
.nullable
) {
647 value
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, value
);
650 function
.add_parameter (new
CCodeParameter ("value", typename
));
652 var array
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("array"));
653 var length
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("length"));
654 var size
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("size"));
656 var renew_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_renew"));
657 renew_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
658 renew_call
.add_argument (array
);
659 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
660 // NULL terminate array
661 renew_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, size
, new
CCodeConstant ("1")));
663 renew_call
.add_argument (size
);
666 var csizecheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, length
, size
);
667 ccode
.open_if (csizecheck
);
668 ccode
.add_assignment (size
, new
CCodeConditionalExpression (size
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("2"), size
), new
CCodeConstant ("4")));
669 ccode
.add_assignment (array
, renew_call
);
672 ccode
.add_assignment (new
CCodeElementAccess (array
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, length
)), value
);
674 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
675 // NULL terminate array
676 ccode
.add_assignment (new
CCodeElementAccess (array
, length
), new
CCodeConstant ("NULL"));
681 cfile
.add_function_declaration (function
);
682 cfile
.add_function (function
);
687 bool is_array_add (Assignment assignment
) {
688 var binary
= assignment
.right as BinaryExpression
;
689 if (binary
!= null && binary
.left
.value_type is ArrayType
) {
690 if (binary
.operator
== BinaryOperator
.PLUS
) {
691 if (assignment
.left
.symbol_reference
== binary
.left
.symbol_reference
) {
700 public override void visit_assignment (Assignment assignment
) {
701 if (!is_array_add (assignment
)) {
702 base.visit_assignment (assignment
);
706 var binary
= (BinaryExpression
) assignment
.right
;
708 var array
= binary
.left
;
709 var array_type
= (ArrayType
) array
.value_type
;
710 var element
= binary
.right
;
712 var array_var
= assignment
.left
.symbol_reference
;
713 if (array_type
.rank
== 1 && array_var
!= null && array_var
.is_internal_symbol ()
714 && (array_var is LocalVariable
|| array_var is Field
)) {
717 Report
.error (assignment
.source_reference
, "Array concatenation not supported for public array variables and parameters");
721 var value_param
= new
Parameter ("value", element
.target_type
);
723 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_add_wrapper (array_type
)));
724 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (array
)));
725 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cexpression (array
)));
726 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_size_cvalue (array
.target_value
)));
727 ccall
.add_argument (handle_struct_argument (value_param
, element
, get_cvalue (element
)));
729 ccode
.add_expression (ccall
);
732 public override CCodeParameter
generate_parameter (Parameter param
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
733 if (!(param
.variable_type is ArrayType
)) {
734 return base.generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
737 string ctypename
= param
.variable_type
.get_cname ();
739 if (param
.direction
!= ParameterDirection
.IN
) {
743 var main_cparam
= new
CCodeParameter (get_variable_cname (param
.name
), ctypename
);
745 var array_type
= (ArrayType
) param
.variable_type
;
747 generate_type_declaration (array_type
.element_type
, decl_space
);
749 cparam_map
.set (get_param_pos (param
.cparameter_position
), main_cparam
);
750 if (carg_map
!= null) {
751 carg_map
.set (get_param_pos (param
.cparameter_position
), get_variable_cexpression (param
.name
));
754 if (!param
.no_array_length
) {
755 string length_ctype
= "int";
756 if (param
.array_length_type
!= null) {
757 length_ctype
= param
.array_length_type
;
759 if (param
.direction
!= ParameterDirection
.IN
) {
760 length_ctype
= "%s*".printf (length_ctype
);
763 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
764 var cparam
= new
CCodeParameter (get_parameter_array_length_cname (param
, dim
), length_ctype
);
765 cparam_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
766 if (carg_map
!= null) {
767 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), get_variable_cexpression (cparam
.name
));