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
);
48 var name_cnode
= get_variable_cexpression (temp_var
.name
);
51 emit_temp_var (temp_var
);
53 append_initializer_list (name_cnode
, expr
.initializer_list
, expr
.rank
, ref i
);
55 set_cvalue (expr
, name_cnode
);
60 CCodeFunctionCall gnew
;
61 if (context
.profile
== Profile
.POSIX
) {
62 cfile
.add_include ("stdlib.h");
63 gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("calloc"));
65 gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
66 gnew
.add_argument (new
CCodeIdentifier (get_ccode_name (expr
.element_type
)));
70 CCodeExpression cexpr
= null;
72 // iterate over each dimension
73 foreach (Expression size
in expr
.get_sizes ()) {
74 CCodeExpression csize
= get_cvalue (size
);
75 append_array_length (expr
, csize
);
81 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cexpr
, csize
);
85 // add extra item to have array NULL-terminated for all reference types
86 if (expr
.element_type
.data_type
!= null && expr
.element_type
.data_type
.is_reference_type ()) {
87 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cexpr
, new
CCodeConstant ("1"));
90 gnew
.add_argument (cexpr
);
92 if (context
.profile
== Profile
.POSIX
) {
93 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
94 csizeof
.add_argument (new
CCodeIdentifier (get_ccode_name (expr
.element_type
)));
95 gnew
.add_argument (csizeof
);
98 var temp_var
= get_temp_variable (expr
.value_type
, true, expr
);
99 var name_cnode
= get_variable_cexpression (temp_var
.name
);
102 emit_temp_var (temp_var
);
104 ccode
.add_assignment (name_cnode
, gnew
);
106 if (expr
.initializer_list
!= null) {
107 append_initializer_list (name_cnode
, expr
.initializer_list
, expr
.rank
, ref i
);
110 set_cvalue (expr
, name_cnode
);
113 public override string get_array_length_cname (string array_cname
, int dim
) {
114 return "%s_length%d".printf (array_cname
, dim
);
117 public override string get_parameter_array_length_cname (Parameter param
, int dim
) {
118 if (get_ccode_array_length_name (param
) != null) {
119 return get_ccode_array_length_name (param
);
121 return get_array_length_cname (get_variable_cname (param
.name
), dim
);
125 public override CCodeExpression
get_array_length_cexpression (Expression array_expr
, int dim
= -1) {
126 return get_array_length_cvalue (array_expr
.target_value
, dim
);
129 public override CCodeExpression
get_array_length_cvalue (TargetValue value
, int dim
= -1) {
130 var array_type
= value
.value_type as ArrayType
;
132 if (array_type
!= null && array_type
.fixed_length
) {
133 return get_ccodenode (array_type
.length
);
136 // dim == -1 => total size over all dimensions
138 if (array_type
!= null && array_type
.rank
> 1) {
139 CCodeExpression cexpr
= get_array_length_cvalue (value
, 1);
140 for (dim
= 2; dim
<= array_type
.rank
; dim
++) {
141 cexpr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cexpr
, get_array_length_cvalue (value
, dim
));
149 List
<CCodeExpression
> size
= ((GLibValue
) value
).array_length_cvalues
;
150 assert (size
!= null && size
.size
>= dim
);
151 return size
[dim
- 1];
154 public override string get_array_size_cname (string array_cname
) {
155 return "_%s_size_".printf (array_cname
);
158 public override void visit_element_access (ElementAccess expr
) {
159 List
<Expression
> indices
= expr
.get_indices ();
160 int rank
= indices
.size
;
162 var ccontainer
= get_cvalue (expr
.container
);
163 var cindex
= get_cvalue (indices
[0]);
164 if (expr
.container
.symbol_reference is ArrayLengthField
) {
165 /* Figure if cindex is a constant expression and calculate dim...*/
166 var lit
= indices
[0] as IntegerLiteral
;
167 var memberaccess
= expr
.container as MemberAccess
;
168 if (lit
!= null && memberaccess
!= null) {
169 int dim
= int.parse (lit
.value
);
170 set_cvalue (expr
, get_array_length_cexpression (memberaccess
.inner
, dim
+ 1));
172 Report
.error (expr
.source_reference
, "only integer literals supported as index");
175 // access to element in an array
176 for (int i
= 1; i
< rank
; i
++) {
177 var cmul
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cindex
, get_array_length_cexpression (expr
.container
, i
+ 1));
178 cindex
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cmul
, get_cvalue (indices
[i
]));
179 if (expr
.container
.is_constant ()) {
180 ccontainer
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, ccontainer
);
183 set_cvalue (expr
, new
CCodeElementAccess (ccontainer
, cindex
));
186 expr
.target_value
.value_type
= expr
.value_type
.copy ();
188 expr
.target_value
= store_temp_value (expr
.target_value
, expr
);
190 ((GLibValue
) expr
.target_value
).lvalue
= true;
193 public override void visit_slice_expression (SliceExpression expr
) {
194 var ccontainer
= get_cvalue (expr
.container
);
195 var cstart
= get_cvalue (expr
.start
);
196 var cstop
= get_cvalue (expr
.stop
);
198 var cstartpointer
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, ccontainer
, cstart
);
199 var splicelen
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, cstop
, cstart
);
201 set_cvalue (expr
, cstartpointer
);
202 append_array_length (expr
, splicelen
);
205 void append_struct_array_free_loop (Struct st
) {
206 var cforinit
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
207 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("array_length"));
208 var cforiter
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("i"), new
CCodeConstant ("1")));
209 ccode
.open_for (cforinit
, cforcond
, cforiter
);
211 var cptrarray
= new
CCodeIdentifier ("array");
212 var cea
= new
CCodeElementAccess (cptrarray
, new
CCodeIdentifier ("i"));
214 var cfreecall
= new
CCodeFunctionCall (get_destroy_func_expression (new
StructValueType (st
)));
215 cfreecall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, cea
));
216 ccode
.add_expression (cfreecall
);
221 public override string?
append_struct_array_free (Struct st
) {
222 string cname
= "_vala_%s_array_free".printf (get_ccode_name (st
));
224 if (cfile
.add_declaration (cname
)) {
228 var fun
= new
CCodeFunction (cname
, "void");
229 fun
.modifiers
= CCodeModifiers
.STATIC
;
230 fun
.add_parameter (new
CCodeParameter ("array", "%s *".printf (get_ccode_name (st
))));
231 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
235 var ccondarr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("array"), new
CCodeConstant ("NULL"));
236 ccode
.open_if (ccondarr
);
238 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
239 append_struct_array_free_loop (st
);
243 var carrfree
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
244 carrfree
.add_argument (new
CCodeIdentifier ("array"));
245 ccode
.add_expression (carrfree
);
249 cfile
.add_function_declaration (fun
);
250 cfile
.add_function (fun
);
255 void append_vala_array_free_loop () {
256 var cforinit
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0"));
257 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("array_length"));
258 var cforiter
= new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("i"), new
CCodeConstant ("1")));
259 ccode
.open_for (cforinit
, cforcond
, cforiter
);
261 var cptrarray
= new
CCodeCastExpression (new
CCodeIdentifier ("array"), "gpointer*");
262 var cea
= new
CCodeElementAccess (cptrarray
, new
CCodeIdentifier ("i"));
264 var cfreecond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, cea
, new
CCodeConstant ("NULL"));
265 ccode
.open_if (cfreecond
);
267 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("destroy_func"));
268 cfreecall
.add_argument (cea
);
269 ccode
.add_expression (cfreecall
);
274 public override void append_vala_array_free () {
275 // _vala_array_destroy only frees elements but not the array itself
277 var fun
= new
CCodeFunction ("_vala_array_destroy", "void");
278 fun
.modifiers
= CCodeModifiers
.STATIC
;
279 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
280 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
281 fun
.add_parameter (new
CCodeParameter ("destroy_func", "GDestroyNotify"));
285 var ccondarr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("array"), new
CCodeConstant ("NULL"));
286 var ccondfunc
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("destroy_func"), new
CCodeConstant ("NULL"));
287 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, ccondarr
, ccondfunc
));
289 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
290 append_vala_array_free_loop ();
296 cfile
.add_function_declaration (fun
);
297 cfile
.add_function (fun
);
299 // _vala_array_free frees elements and array
301 fun
= new
CCodeFunction ("_vala_array_free", "void");
302 fun
.modifiers
= CCodeModifiers
.STATIC
;
303 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
304 fun
.add_parameter (new
CCodeParameter ("array_length", "gint"));
305 fun
.add_parameter (new
CCodeParameter ("destroy_func", "GDestroyNotify"));
309 // call _vala_array_destroy to free the array elements
310 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
311 ccall
.add_argument (new
CCodeIdentifier ("array"));
312 ccall
.add_argument (new
CCodeIdentifier ("array_length"));
313 ccall
.add_argument (new
CCodeIdentifier ("destroy_func"));
314 ccode
.add_expression (ccall
);
316 var carrfree
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
317 carrfree
.add_argument (new
CCodeIdentifier ("array"));
318 ccode
.add_expression (carrfree
);
322 cfile
.add_function_declaration (fun
);
323 cfile
.add_function (fun
);
326 public override void append_vala_array_move () {
327 cfile
.add_include ("string.h");
329 // assumes that overwritten array elements are null before invocation
330 // FIXME will leak memory if that's not the case
331 var fun
= new
CCodeFunction ("_vala_array_move", "void");
332 fun
.modifiers
= CCodeModifiers
.STATIC
;
333 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
334 fun
.add_parameter (new
CCodeParameter ("element_size", "gsize"));
335 fun
.add_parameter (new
CCodeParameter ("src", "gint"));
336 fun
.add_parameter (new
CCodeParameter ("dest", "gint"));
337 fun
.add_parameter (new
CCodeParameter ("length", "gint"));
341 var array
= new
CCodeCastExpression (new
CCodeIdentifier ("array"), "char*");
342 var element_size
= new
CCodeIdentifier ("element_size");
343 var length
= new
CCodeIdentifier ("length");
344 var src
= new
CCodeIdentifier ("src");
345 var src_end
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, src
, length
);
346 var dest
= new
CCodeIdentifier ("dest");
347 var dest_end
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, dest
, length
);
348 var src_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, src
, element_size
));
349 var dest_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, dest
, element_size
));
350 var dest_end_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, dest_end
, element_size
));
352 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memmove"));
353 ccall
.add_argument (dest_address
);
354 ccall
.add_argument (src_address
);
355 ccall
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, length
, element_size
));
356 ccode
.add_expression (ccall
);
358 ccode
.open_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, src
, dest
), new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, src_end
, dest
)));
360 var czero1
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
361 czero1
.add_argument (src_address
);
362 czero1
.add_argument (new
CCodeConstant ("0"));
363 czero1
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, dest
, src
), element_size
));
364 ccode
.add_expression (czero1
);
366 ccode
.else_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, src
, dest
), new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, src
, dest_end
)));
368 var czero2
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
369 czero2
.add_argument (dest_end_address
);
370 czero2
.add_argument (new
CCodeConstant ("0"));
371 czero2
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, src
, dest
), element_size
));
372 ccode
.add_expression (czero2
);
374 ccode
.else_if (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, src
, dest
));
376 var czero3
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
377 czero3
.add_argument (src_address
);
378 czero3
.add_argument (new
CCodeConstant ("0"));
379 czero3
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, length
, element_size
));
380 ccode
.add_expression (czero3
);
386 cfile
.add_function_declaration (fun
);
387 cfile
.add_function (fun
);
390 public override void append_vala_array_length () {
391 var fun
= new
CCodeFunction ("_vala_array_length", "gint");
392 fun
.modifiers
= CCodeModifiers
.STATIC
;
393 fun
.add_parameter (new
CCodeParameter ("array", "gpointer"));
397 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("length", new
CCodeConstant ("0")));
399 // return 0 if the array is NULL
400 // avoids an extra NULL check on the caller side
401 var array_check
= new
CCodeIdentifier ("array");
402 ccode
.open_if (array_check
);
404 var array_element_check
= new
CCodeElementAccess (new
CCodeCastExpression (new
CCodeIdentifier ("array"), "gpointer*"), new
CCodeConstant ("length"));
405 ccode
.open_while (array_element_check
);
406 ccode
.add_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("length")));
411 ccode
.add_return (new
CCodeIdentifier ("length"));
415 cfile
.add_function_declaration (fun
);
416 cfile
.add_function (fun
);
419 public override TargetValue?
copy_value (TargetValue value
, CodeNode node
) {
420 var type
= value
.value_type
;
421 var cexpr
= get_cvalue_ (value
);
423 if (type is ArrayType
) {
424 var array_type
= (ArrayType
) type
;
426 if (!array_type
.fixed_length
) {
427 return base.copy_value (value
, node
);
430 var temp_value
= create_temp_value (type
, false, node
);
432 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_copy_wrapper (array_type
)));
433 copy_call
.add_argument (cexpr
);
434 copy_call
.add_argument (get_cvalue_ (temp_value
));
435 ccode
.add_expression (copy_call
);
439 return base.copy_value (value
, node
);
443 public override CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
, bool is_chainup
) {
444 if (type is ArrayType
) {
445 var array_type
= (ArrayType
) type
;
446 // fixed length arrays use different code
447 // generated by overridden get_ref_cexpression method
448 assert (!array_type
.fixed_length
);
449 return new
CCodeIdentifier (generate_array_dup_wrapper (array_type
));
451 return base.get_dup_func_expression (type
, source_reference
, is_chainup
);
455 public override CCodeExpression
destroy_value (TargetValue value
, bool is_macro_definition
= false) {
456 var type
= value
.value_type
;
458 if (type is ArrayType
) {
459 var array_type
= (ArrayType
) type
;
461 if (!array_type
.fixed_length
) {
462 return base.destroy_value (value
, is_macro_definition
);
465 requires_array_free
= true;
467 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
469 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
470 ccall
.add_argument (get_cvalue_ (value
));
471 ccall
.add_argument (get_ccodenode (array_type
.length
));
472 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
476 return base.destroy_value (value
, is_macro_definition
);
480 string generate_array_dup_wrapper (ArrayType array_type
) {
481 string dup_func
= "_vala_array_dup%d".printf (++next_array_dup_id
);
483 if (!add_wrapper (dup_func
)) {
484 // wrapper already defined
490 var function
= new
CCodeFunction (dup_func
, get_ccode_name (array_type
));
491 function
.modifiers
= CCodeModifiers
.STATIC
;
493 function
.add_parameter (new
CCodeParameter ("self", get_ccode_name (array_type
)));
494 // total length over all dimensions
495 function
.add_parameter (new
CCodeParameter ("length", "int"));
496 if (array_type
.element_type is GenericType
) {
497 // dup function array elements
498 string func_name
= "%s_dup_func".printf (((GenericType
) array_type
.element_type
).type_parameter
.name
.down ());
499 function
.add_parameter (new
CCodeParameter (func_name
, "GBoxedCopyFunc"));
504 push_context (new
EmitContext ());
505 push_function (function
);
507 if (requires_copy (array_type
.element_type
)) {
508 var cvardecl
= new
CCodeVariableDeclarator ("result");
509 var gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
510 gnew
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
512 CCodeExpression length_expr
= new
CCodeIdentifier ("length");
513 // add extra item to have array NULL-terminated for all reference types
514 if (array_type
.element_type
.data_type
!= null && array_type
.element_type
.data_type
.is_reference_type ()) {
515 length_expr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, length_expr
, new
CCodeConstant ("1"));
517 gnew
.add_argument (length_expr
);
519 ccode
.add_declaration (get_ccode_name (array_type
), cvardecl
);
520 ccode
.add_assignment (new
CCodeIdentifier ("result"), gnew
);
522 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
524 ccode
.open_for (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")),
525 new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("length")),
526 new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
528 ccode
.add_assignment (new
CCodeElementAccess (new
CCodeIdentifier ("result"), new
CCodeIdentifier ("i")), get_cvalue_ (copy_value (new
GLibValue (array_type
.element_type
, new
CCodeElementAccess (new
CCodeIdentifier ("self"), new
CCodeIdentifier ("i")), true), array_type
)));
531 ccode
.add_return (new
CCodeIdentifier ("result"));
533 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memdup"));
534 dup_call
.add_argument (new
CCodeIdentifier ("self"));
536 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
537 sizeof_call
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
538 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeIdentifier ("length"), sizeof_call
));
540 ccode
.add_return (dup_call
);
545 cfile
.add_function_declaration (function
);
546 cfile
.add_function (function
);
553 string generate_array_copy_wrapper (ArrayType array_type
) {
554 string dup_func
= "_vala_array_copy%d".printf (++next_array_dup_id
);
556 if (!add_wrapper (dup_func
)) {
557 // wrapper already defined
563 var function
= new
CCodeFunction (dup_func
, "void");
564 function
.modifiers
= CCodeModifiers
.STATIC
;
566 function
.add_parameter (new
CCodeParameter ("self", "%s *".printf (get_ccode_name (array_type
))));
567 function
.add_parameter (new
CCodeParameter ("dest", "%s *".printf (get_ccode_name (array_type
))));
571 push_context (new
EmitContext ());
572 push_function (function
);
574 if (requires_copy (array_type
.element_type
)) {
575 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("i"));
577 ccode
.open_for (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")),
578 new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), get_ccodenode (array_type
.length
)),
579 new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
582 ccode
.add_assignment (new
CCodeElementAccess (new
CCodeIdentifier ("dest"), new
CCodeIdentifier ("i")), get_cvalue_ (copy_value (new
GLibValue (array_type
.element_type
, new
CCodeElementAccess (new
CCodeIdentifier ("self"), new
CCodeIdentifier ("i")), true), array_type
)));
584 cfile
.add_include ("string.h");
586 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
587 dup_call
.add_argument (new
CCodeIdentifier ("dest"));
588 dup_call
.add_argument (new
CCodeIdentifier ("self"));
590 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
591 sizeof_call
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
592 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, get_ccodenode (array_type
.length
), sizeof_call
));
594 ccode
.add_expression (dup_call
);
599 cfile
.add_function_declaration (function
);
600 cfile
.add_function (function
);
607 string generate_array_add_wrapper (ArrayType array_type
) {
608 string add_func
= "_vala_array_add%d".printf (++next_array_add_id
);
610 if (!add_wrapper (add_func
)) {
611 // wrapper already defined
615 var function
= new
CCodeFunction (add_func
, "void");
616 function
.modifiers
= CCodeModifiers
.STATIC
;
618 function
.add_parameter (new
CCodeParameter ("array", "%s *".printf (get_ccode_name (array_type
))));
619 function
.add_parameter (new
CCodeParameter ("length", "int*"));
620 function
.add_parameter (new
CCodeParameter ("size", "int*"));
622 push_function (function
);
624 string typename
= get_ccode_name (array_type
.element_type
);
625 CCodeExpression value
= new
CCodeIdentifier ("value");
626 if (array_type
.element_type
.is_real_struct_type ()) {
627 if (!array_type
.element_type
.nullable
|| !array_type
.element_type
.value_owned
) {
628 typename
= "const " + typename
;
630 if (!array_type
.element_type
.nullable
) {
632 value
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, value
);
635 function
.add_parameter (new
CCodeParameter ("value", typename
));
637 var array
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("array"));
638 var length
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("length"));
639 var size
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("size"));
641 var renew_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_renew"));
642 renew_call
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
643 renew_call
.add_argument (array
);
644 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
645 // NULL terminate array
646 renew_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, size
, new
CCodeConstant ("1")));
648 renew_call
.add_argument (size
);
651 var csizecheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, length
, size
);
652 ccode
.open_if (csizecheck
);
653 ccode
.add_assignment (size
, new
CCodeConditionalExpression (size
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("2"), size
), new
CCodeConstant ("4")));
654 ccode
.add_assignment (array
, renew_call
);
657 ccode
.add_assignment (new
CCodeElementAccess (array
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, length
)), value
);
659 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
660 // NULL terminate array
661 ccode
.add_assignment (new
CCodeElementAccess (array
, length
), new
CCodeConstant ("NULL"));
666 cfile
.add_function_declaration (function
);
667 cfile
.add_function (function
);
672 bool is_array_add (Assignment assignment
) {
673 var binary
= assignment
.right as BinaryExpression
;
674 if (binary
!= null && binary
.left
.value_type is ArrayType
) {
675 if (binary
.operator
== BinaryOperator
.PLUS
) {
676 if (assignment
.left
.symbol_reference
== binary
.left
.symbol_reference
) {
685 public override void visit_assignment (Assignment assignment
) {
686 if (!is_array_add (assignment
)) {
687 base.visit_assignment (assignment
);
691 var binary
= (BinaryExpression
) assignment
.right
;
693 var array
= assignment
.left
;
694 var array_type
= (ArrayType
) array
.value_type
;
695 var element
= binary
.right
;
697 var array_var
= array
.symbol_reference
;
698 if (array_type
.rank
== 1 && array_var
!= null && array_var
.is_internal_symbol ()
699 && (array_var is LocalVariable
|| array_var is Field
)) {
702 Report
.error (assignment
.source_reference
, "Array concatenation not supported for public array variables and parameters");
706 var value_param
= new
Parameter ("value", element
.target_type
);
708 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_add_wrapper (array_type
)));
709 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (array
)));
710 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cexpression (array
)));
711 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_size_cvalue (array
.target_value
)));
712 ccall
.add_argument (handle_struct_argument (value_param
, element
, get_cvalue (element
)));
714 ccode
.add_expression (ccall
);
717 public override CCodeParameter
generate_parameter (Parameter param
, CCodeFile decl_space
, Map
<int,CCodeParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
718 if (!(param
.variable_type is ArrayType
)) {
719 return base.generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
722 string ctypename
= get_ccode_name (param
.variable_type
);
724 if (param
.direction
!= ParameterDirection
.IN
) {
728 var main_cparam
= new
CCodeParameter (get_variable_cname (param
.name
), ctypename
);
730 var array_type
= (ArrayType
) param
.variable_type
;
732 generate_type_declaration (array_type
.element_type
, decl_space
);
734 cparam_map
.set (get_param_pos (get_ccode_pos (param
)), main_cparam
);
735 if (carg_map
!= null) {
736 carg_map
.set (get_param_pos (get_ccode_pos (param
)), get_variable_cexpression (param
.name
));
739 if (get_ccode_array_length (param
)) {
740 string length_ctype
= "int";
741 if (get_ccode_array_length_type (param
) != null) {
742 length_ctype
= get_ccode_array_length_type (param
);
744 if (param
.direction
!= ParameterDirection
.IN
) {
745 length_ctype
= "%s*".printf (length_ctype
);
748 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
749 var cparam
= new
CCodeParameter (get_parameter_array_length_cname (param
, dim
), length_ctype
);
750 cparam_map
.set (get_param_pos (get_ccode_array_length_pos (param
) + 0.01 * dim
), cparam
);
751 if (carg_map
!= null) {
752 carg_map
.set (get_param_pos (get_ccode_array_length_pos (param
) + 0.01 * dim
), get_variable_cexpression (cparam
.name
));