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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
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
) {
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 ()) {
38 append_initializer_list (ce
, name_cnode
, (InitializerList
) e
, rank
- 1, ref i
);
40 ce
.append_expression (new
CCodeAssignment (new
CCodeElementAccess (name_cnode
, new
CCodeConstant (i
.to_string ())), (CCodeExpression
) e
.ccodenode
));
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
);
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
);
69 var gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
70 gnew
.add_argument (new
CCodeIdentifier (expr
.element_type
.get_cname ()));
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
);
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
);
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
);
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
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
));
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
;
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
));
177 // passing array as out/ref
178 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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
));
185 // passing array as out/ref
186 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, length_expr
);
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
);
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
);
204 // passing array as out/ref
205 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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
));
218 // passing array as out/ref
219 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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
));
226 // passing array as out/ref
227 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, length_expr
);
232 var length_expr
= get_variable_cexpression (get_array_length_cname (get_variable_cname (local
.name
), dim
));
234 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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");
259 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
260 carray_expr
= new CCodeMemberAccess
.pointer (inst
, array_cname
);
262 carray_expr
= new
CCodeMemberAccess (inst
, array_cname
);
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
);
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
);
284 if (field
.has_array_length_cname
) {
285 length_cname
= field
.get_array_length_cname ();
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");
297 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
298 length_expr
= new CCodeMemberAccess
.pointer (inst
, length_cname
);
300 length_expr
= new
CCodeMemberAccess (inst
, length_cname
);
303 length_expr
= new
CCodeIdentifier (get_array_length_cname (field
.get_cname (), dim
));
307 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, 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 ()));
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");
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");
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");
370 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
371 size_expr
= new CCodeMemberAccess
.pointer (inst
, size_cname
);
373 size_expr
= new
CCodeMemberAccess (inst
, size_cname
);
376 size_expr
= new
CCodeIdentifier (get_array_size_cname (field
.get_cname ()));
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
;
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"))));
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
)) {
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
);
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"))));
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")));
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
);
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
));
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"));
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
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"));
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
;
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
));
762 source_declarations
.add_type_member_declaration (function
.copy ());
764 function
.block
= block
;
765 source_type_member_definition
.append (function
);
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
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 () + "*"));
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
;
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
));
828 source_declarations
.add_type_member_declaration (function
.copy ());
830 function
.block
= block
;
831 source_type_member_definition
.append (function
);
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
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
) {
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"));
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")));
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"))));
900 source_declarations
.add_type_member_declaration (function
.copy ());
902 function
.block
= block
;
903 source_type_member_definition
.append (function
);
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
) {
921 public override void visit_assignment (Assignment assignment
) {
922 if (!is_array_add (assignment
)) {
923 base.visit_assignment (assignment
);
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
);
954 string ctypename
= param
.parameter_type
.get_cname ();
956 if (param
.direction
!= ParameterDirection
.IN
) {
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
));