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
= new
CCodeIdentifier (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
= new
CCodeIdentifier (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
= new
CCodeIdentifier (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
) {
165 var invocation_expr
= (MethodCall
) array_expr
;
166 Gee
.List
<CCodeExpression
> size
= invocation_expr
.get_array_sizes ();
167 return size
[dim
- 1];
168 } else if (array_expr
.symbol_reference
!= null) {
169 if (array_expr
.symbol_reference is FormalParameter
) {
170 var param
= (FormalParameter
) array_expr
.symbol_reference
;
171 if (param
.array_null_terminated
) {
172 var carray_expr
= get_variable_cexpression (param
.name
);
173 requires_array_length
= true;
174 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
175 len_call
.add_argument (carray_expr
);
177 } else if (!param
.no_array_length
) {
178 CCodeExpression length_expr
= get_variable_cexpression (get_array_length_cname (param
.name
, dim
));
179 if (param
.direction
!= ParameterDirection
.IN
) {
180 // accessing argument of out/ref param
181 length_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, length_expr
);
184 // passing array as out/ref
185 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, length_expr
);
190 } else if (array_expr
.symbol_reference is LocalVariable
) {
191 var local
= (LocalVariable
) array_expr
.symbol_reference
;
192 var length_expr
= get_variable_cexpression (get_array_length_cname (get_variable_cname (local
.name
), dim
));
194 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, length_expr
);
198 } else if (array_expr
.symbol_reference is Field
) {
199 var field
= (Field
) array_expr
.symbol_reference
;
200 if (field
.array_null_terminated
) {
201 var ma
= (MemberAccess
) array_expr
;
203 CCodeExpression carray_expr
= null;
205 if (field
.binding
== MemberBinding
.INSTANCE
) {
206 var cl
= field
.parent_symbol as Class
;
207 bool is_gtypeinstance
= (cl
!= null && !cl
.is_compact
);
209 string array_cname
= field
.get_cname ();
210 CCodeExpression typed_inst
= (CCodeExpression
) get_ccodenode (ma
.inner
);
212 CCodeExpression inst
;
213 if (is_gtypeinstance
&& field
.access
== SymbolAccessibility
.PRIVATE
) {
214 inst
= new CCodeMemberAccess
.pointer (typed_inst
, "priv");
218 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
219 carray_expr
= new CCodeMemberAccess
.pointer (inst
, array_cname
);
221 carray_expr
= new
CCodeMemberAccess (inst
, array_cname
);
224 carray_expr
= new
CCodeIdentifier (field
.get_cname ());
227 requires_array_length
= true;
228 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
229 len_call
.add_argument (carray_expr
);
231 } else if (!field
.no_array_length
) {
232 var ma
= (MemberAccess
) array_expr
;
234 CCodeExpression length_expr
= null;
236 if (field
.has_array_length_cexpr
) {
237 length_expr
= new
CCodeConstant (field
.get_array_length_cexpr ());
238 } else if (field
.binding
== MemberBinding
.INSTANCE
) {
239 var cl
= field
.parent_symbol as Class
;
240 bool is_gtypeinstance
= (cl
!= null && !cl
.is_compact
);
243 if (field
.has_array_length_cname
) {
244 length_cname
= field
.get_array_length_cname ();
246 length_cname
= get_array_length_cname (field
.name
, dim
);
248 CCodeExpression typed_inst
= (CCodeExpression
) get_ccodenode (ma
.inner
);
250 CCodeExpression inst
;
251 if (is_gtypeinstance
&& field
.access
== SymbolAccessibility
.PRIVATE
) {
252 inst
= new CCodeMemberAccess
.pointer (typed_inst
, "priv");
256 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
257 length_expr
= new CCodeMemberAccess
.pointer (inst
, length_cname
);
259 length_expr
= new
CCodeMemberAccess (inst
, length_cname
);
262 length_expr
= new
CCodeIdentifier (get_array_length_cname (field
.get_cname (), dim
));
266 return new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, length_expr
);
271 } else if (array_expr
.symbol_reference is Constant
) {
272 var constant
= (Constant
) array_expr
.symbol_reference
;
273 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_N_ELEMENTS"));
274 ccall
.add_argument (new
CCodeIdentifier (constant
.get_cname ()));
277 } else if (array_expr is NullLiteral
) {
278 return new
CCodeConstant ("0");
282 /* allow arrays with unknown length even for value types
283 * as else it may be impossible to bind some libraries
284 * users of affected libraries should explicitly set
285 * the array length as early as possible
286 * by setting the virtual length field of the array
288 return new
CCodeConstant ("-1");
290 return new
CCodeConstant ("NULL");
294 public override string get_array_size_cname (string array_cname
) {
295 return "%s_size".printf (array_cname
);
298 public override CCodeExpression
get_array_size_cexpression (Expression array_expr
) {
299 if (array_expr
.symbol_reference is LocalVariable
) {
300 var local
= (LocalVariable
) array_expr
.symbol_reference
;
301 return get_variable_cexpression (get_array_size_cname (get_variable_cname (local
.name
)));
302 } else if (array_expr
.symbol_reference is Field
) {
303 var field
= (Field
) array_expr
.symbol_reference
;
304 var ma
= (MemberAccess
) array_expr
;
306 CCodeExpression size_expr
= null;
308 if (field
.binding
== MemberBinding
.INSTANCE
) {
309 var cl
= field
.parent_symbol as Class
;
310 bool is_gtypeinstance
= (cl
!= null && !cl
.is_compact
);
312 string size_cname
= get_array_size_cname (field
.name
);
313 CCodeExpression typed_inst
= (CCodeExpression
) get_ccodenode (ma
.inner
);
315 CCodeExpression inst
;
316 if (is_gtypeinstance
&& field
.access
== SymbolAccessibility
.PRIVATE
) {
317 inst
= new CCodeMemberAccess
.pointer (typed_inst
, "priv");
321 if (((TypeSymbol
) field
.parent_symbol
).is_reference_type ()) {
322 size_expr
= new CCodeMemberAccess
.pointer (inst
, size_cname
);
324 size_expr
= new
CCodeMemberAccess (inst
, size_cname
);
327 size_expr
= new
CCodeIdentifier (get_array_size_cname (field
.get_cname ()));
333 assert_not_reached ();
336 public override void visit_element_access (ElementAccess expr
) {
337 expr
.accept_children (codegen
);
339 Gee
.List
<Expression
> indices
= expr
.get_indices ();
340 int rank
= indices
.size
;
342 var container_type
= expr
.container
.value_type
.data_type
;
344 var ccontainer
= (CCodeExpression
) expr
.container
.ccodenode
;
345 var cindex
= (CCodeExpression
) indices
[0].ccodenode
;
346 if (expr
.container
.symbol_reference is ArrayLengthField
) {
347 /* Figure if cindex is a constant expression and calculate dim...*/
348 var lit
= indices
[0] as IntegerLiteral
;
349 var memberaccess
= expr
.container as MemberAccess
;
350 if (lit
!= null && memberaccess
!= null) {
351 int dim
= lit
.value
.to_int ();
352 expr
.ccodenode
= head
.get_array_length_cexpression (memberaccess
.inner
, dim
+ 1);
354 } else if (container_type
== string_type
.data_type
) {
355 // should be moved to a different module
357 // access to unichar in a string
358 var coffsetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_utf8_offset_to_pointer"));
359 coffsetcall
.add_argument (ccontainer
);
360 coffsetcall
.add_argument (cindex
);
362 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_utf8_get_char"));
363 ccall
.add_argument (coffsetcall
);
365 expr
.ccodenode
= ccall
;
367 // access to element in an array
368 for (int i
= 1; i
< rank
; i
++) {
369 var cmul
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, cindex
, head
.get_array_length_cexpression (expr
.container
, i
+ 1));
370 cindex
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, cmul
, (CCodeExpression
) indices
[i
].ccodenode
);
372 expr
.ccodenode
= new
CCodeElementAccess (ccontainer
, cindex
);
376 private CCodeForStatement
get_vala_array_free_loop () {
377 var cbody
= new
CCodeBlock ();
378 var cptrarray
= new
CCodeCastExpression (new
CCodeIdentifier ("array"), "gpointer*");
379 var cea
= new
CCodeElementAccess (cptrarray
, new
CCodeIdentifier ("i"));
381 var cfreecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("destroy_func"));
382 cfreecall
.add_argument (cea
);
384 var cfreecond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, cea
, new
CCodeConstant ("NULL"));
385 var cforcond
= new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("array_length"));
386 var cfreeblock
= new
CCodeBlock ();
387 cfreeblock
.add_statement (new
CCodeExpressionStatement (cfreecall
));
388 cbody
.add_statement (new
CCodeIfStatement (cfreecond
, cfreeblock
));
390 var cfor
= new
CCodeForStatement (cforcond
, cbody
);
391 cfor
.add_initializer (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")));
392 cfor
.add_iterator (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("i"), new
CCodeConstant ("1"))));
397 public override void append_vala_array_free () {
398 // _vala_array_destroy only frees elements but not the array itself
400 var fun
= new
CCodeFunction ("_vala_array_destroy", "void");
401 fun
.modifiers
= CCodeModifiers
.STATIC
;
402 fun
.add_parameter (new
CCodeFormalParameter ("array", "gpointer"));
403 fun
.add_parameter (new
CCodeFormalParameter ("array_length", "gint"));
404 fun
.add_parameter (new
CCodeFormalParameter ("destroy_func", "GDestroyNotify"));
405 source_declarations
.add_type_member_declaration (fun
.copy ());
407 var cdofree
= new
CCodeBlock ();
409 var citdecl
= new
CCodeDeclaration ("int");
410 citdecl
.add_declarator (new
CCodeVariableDeclarator ("i"));
411 cdofree
.add_statement (citdecl
);
413 cdofree
.add_statement (get_vala_array_free_loop ());
415 var ccondarr
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("array"), new
CCodeConstant ("NULL"));
416 var ccondfunc
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("destroy_func"), new
CCodeConstant ("NULL"));
417 var cif
= new
CCodeIfStatement (new
CCodeBinaryExpression (CCodeBinaryOperator
.AND
, ccondarr
, ccondfunc
), cdofree
);
418 fun
.block
= new
CCodeBlock ();
419 fun
.block
.add_statement (cif
);
421 source_type_member_definition
.append (fun
);
423 // _vala_array_free frees elements and array
425 fun
= new
CCodeFunction ("_vala_array_free", "void");
426 fun
.modifiers
= CCodeModifiers
.STATIC
;
427 fun
.add_parameter (new
CCodeFormalParameter ("array", "gpointer"));
428 fun
.add_parameter (new
CCodeFormalParameter ("array_length", "gint"));
429 fun
.add_parameter (new
CCodeFormalParameter ("destroy_func", "GDestroyNotify"));
430 source_declarations
.add_type_member_declaration (fun
.copy ());
432 // call _vala_array_destroy to free the array elements
433 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
434 ccall
.add_argument (new
CCodeIdentifier ("array"));
435 ccall
.add_argument (new
CCodeIdentifier ("array_length"));
436 ccall
.add_argument (new
CCodeIdentifier ("destroy_func"));
438 fun
.block
= new
CCodeBlock ();
439 fun
.block
.add_statement (new
CCodeExpressionStatement (ccall
));
441 var carrfree
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_free"));
442 carrfree
.add_argument (new
CCodeIdentifier ("array"));
443 fun
.block
.add_statement (new
CCodeExpressionStatement (carrfree
));
445 source_type_member_definition
.append (fun
);
448 public override void append_vala_array_move () {
449 source_declarations
.add_include ("string.h");
451 // assumes that overwritten array elements are null before invocation
452 // FIXME will leak memory if that's not the case
453 var fun
= new
CCodeFunction ("_vala_array_move", "void");
454 fun
.modifiers
= CCodeModifiers
.STATIC
;
455 fun
.add_parameter (new
CCodeFormalParameter ("array", "gpointer"));
456 fun
.add_parameter (new
CCodeFormalParameter ("element_size", "gsize"));
457 fun
.add_parameter (new
CCodeFormalParameter ("src", "gint"));
458 fun
.add_parameter (new
CCodeFormalParameter ("dest", "gint"));
459 fun
.add_parameter (new
CCodeFormalParameter ("length", "gint"));
460 source_declarations
.add_type_member_declaration (fun
.copy ());
462 var array
= new
CCodeCastExpression (new
CCodeIdentifier ("array"), "char*");
463 var element_size
= new
CCodeIdentifier ("element_size");
464 var length
= new
CCodeIdentifier ("length");
465 var src
= new
CCodeIdentifier ("src");
466 var dest
= new
CCodeIdentifier ("dest");
467 var src_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, src
, element_size
));
468 var dest_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, dest
, element_size
));
469 var dest_end_address
= new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, array
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, dest
, length
), element_size
));
471 fun
.block
= new
CCodeBlock ();
473 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memmove"));
474 ccall
.add_argument (dest_address
);
475 ccall
.add_argument (src_address
);
476 ccall
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, length
, element_size
));
477 fun
.block
.add_statement (new
CCodeExpressionStatement (ccall
));
479 var czero1
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
480 czero1
.add_argument (src_address
);
481 czero1
.add_argument (new
CCodeConstant ("0"));
482 czero1
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, dest
, src
), element_size
));
483 var czeroblock1
= new
CCodeBlock ();
484 czeroblock1
.add_statement (new
CCodeExpressionStatement (czero1
));
486 var czero2
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
487 czero2
.add_argument (dest_end_address
);
488 czero2
.add_argument (new
CCodeConstant ("0"));
489 czero2
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, src
, dest
), element_size
));
490 var czeroblock2
= new
CCodeBlock ();
491 czeroblock2
.add_statement (new
CCodeExpressionStatement (czero2
));
493 fun
.block
.add_statement (new
CCodeIfStatement (new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, src
, dest
), czeroblock1
, czeroblock2
));
495 source_type_member_definition
.append (fun
);
498 public override void append_vala_array_length () {
499 var fun
= new
CCodeFunction ("_vala_array_length", "gint");
500 fun
.modifiers
= CCodeModifiers
.STATIC
;
501 fun
.add_parameter (new
CCodeFormalParameter ("array", "gpointer"));
502 source_declarations
.add_type_member_declaration (fun
.copy ());
504 var block
= new
CCodeBlock ();
506 var len_decl
= new
CCodeDeclaration ("int");
507 len_decl
.add_declarator (new
CCodeVariableDeclarator ("length", new
CCodeConstant ("0")));
508 block
.add_statement (len_decl
);
510 var non_null_block
= new
CCodeBlock ();
512 var while_body
= new
CCodeBlock ();
513 while_body
.add_statement (new
CCodeExpressionStatement (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("length"))));
515 var array_element_check
= new
CCodeElementAccess (new
CCodeCastExpression (new
CCodeIdentifier ("array"), "gpointer*"), new
CCodeConstant ("length"));
516 non_null_block
.add_statement (new
CCodeWhileStatement (array_element_check
, while_body
));
518 // return 0 if the array is NULL
519 // avoids an extra NULL check on the caller side
520 var array_check
= new
CCodeIdentifier ("array");
521 block
.add_statement (new
CCodeIfStatement (array_check
, non_null_block
));
523 block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("length")));
527 source_type_member_definition
.append (fun
);
530 public override CCodeExpression?
get_ref_cexpression (DataType expression_type
, CCodeExpression cexpr
, Expression? expr
, CodeNode node
) {
531 if (expression_type is ArrayType
) {
532 var array_type
= (ArrayType
) expression_type
;
534 if (!array_type
.fixed_length
) {
535 return base.get_ref_cexpression (expression_type
, cexpr
, expr
, node
);
538 var decl
= get_temp_variable (expression_type
, false, node
);
539 temp_vars
.insert (0, decl
);
541 var ctemp
= get_variable_cexpression (decl
.name
);
543 var copy_call
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_copy_wrapper (array_type
)));
544 copy_call
.add_argument (cexpr
);
545 copy_call
.add_argument (ctemp
);
547 var ccomma
= new
CCodeCommaExpression ();
549 ccomma
.append_expression (copy_call
);
550 ccomma
.append_expression (ctemp
);
554 return base.get_ref_cexpression (expression_type
, cexpr
, expr
, node
);
558 public override CCodeExpression?
get_dup_func_expression (DataType type
, SourceReference? source_reference
) {
559 if (type is ArrayType
) {
560 var array_type
= (ArrayType
) type
;
561 // fixed length arrays use different code
562 // generated by overridden get_ref_cexpression method
563 assert (!array_type
.fixed_length
);
564 return new
CCodeIdentifier (generate_array_dup_wrapper (array_type
));
566 return base.get_dup_func_expression (type
, source_reference
);
570 public override CCodeExpression
get_unref_expression (CCodeExpression cvar
, DataType type
, Expression expr
) {
571 if (type is ArrayType
) {
572 var array_type
= (ArrayType
) type
;
574 if (!array_type
.fixed_length
) {
575 return base.get_unref_expression (cvar
, type
, expr
);
578 requires_array_free
= true;
580 var ccall
= new
CCodeFunctionCall (get_destroy_func_expression (type
));
582 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_destroy"));
583 ccall
.add_argument (cvar
);
584 ccall
.add_argument (new
CCodeConstant ("%d".printf (array_type
.length
)));
585 ccall
.add_argument (new
CCodeCastExpression (get_destroy_func_expression (array_type
.element_type
), "GDestroyNotify"));
589 return base.get_unref_expression (cvar
, type
, expr
);
593 string generate_array_dup_wrapper (ArrayType array_type
) {
594 string dup_func
= "_vala_array_dup%d".printf (++next_array_dup_id
);
596 if (!add_wrapper (dup_func
)) {
597 // wrapper already defined
603 var function
= new
CCodeFunction (dup_func
, array_type
.get_cname ());
604 function
.modifiers
= CCodeModifiers
.STATIC
;
606 function
.add_parameter (new
CCodeFormalParameter ("self", array_type
.get_cname ()));
607 // total length over all dimensions
608 function
.add_parameter (new
CCodeFormalParameter ("length", "int"));
612 var block
= new
CCodeBlock ();
614 if (requires_copy (array_type
.element_type
)) {
615 var old_temp_vars
= temp_vars
;
617 var cdecl
= new
CCodeDeclaration (array_type
.get_cname ());
618 var cvardecl
= new
CCodeVariableDeclarator ("result");
619 cdecl
.add_declarator (cvardecl
);
620 var gnew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
621 gnew
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
622 gnew
.add_argument (new
CCodeIdentifier ("length"));
623 cvardecl
.initializer
= gnew
;
624 block
.add_statement (cdecl
);
626 var idx_decl
= new
CCodeDeclaration ("int");
627 idx_decl
.add_declarator (new
CCodeVariableDeclarator ("i"));
628 block
.add_statement (idx_decl
);
630 var loop_body
= new
CCodeBlock ();
631 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
))));
633 var cfor
= new
CCodeForStatement (new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeIdentifier ("length")), loop_body
);
634 cfor
.add_initializer (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")));
635 cfor
.add_iterator (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
636 block
.add_statement (cfor
);
638 block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("result")));
640 var cfrag
= new
CCodeFragment ();
641 append_temp_decl (cfrag
, temp_vars
);
642 block
.add_statement (cfrag
);
643 temp_vars
= old_temp_vars
;
645 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_memdup"));
646 dup_call
.add_argument (new
CCodeIdentifier ("self"));
648 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
649 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
650 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeIdentifier ("length"), sizeof_call
));
652 block
.add_statement (new
CCodeReturnStatement (dup_call
));
657 source_declarations
.add_type_member_declaration (function
.copy ());
659 function
.block
= block
;
660 source_type_member_definition
.append (function
);
665 string generate_array_copy_wrapper (ArrayType array_type
) {
666 string dup_func
= "_vala_array_copy%d".printf (++next_array_dup_id
);
668 if (!add_wrapper (dup_func
)) {
669 // wrapper already defined
675 var function
= new
CCodeFunction (dup_func
, "void");
676 function
.modifiers
= CCodeModifiers
.STATIC
;
678 function
.add_parameter (new
CCodeFormalParameter ("self", array_type
.get_cname () + "*"));
679 function
.add_parameter (new
CCodeFormalParameter ("dest", array_type
.get_cname () + "*"));
683 var block
= new
CCodeBlock ();
685 if (requires_copy (array_type
.element_type
)) {
686 var old_temp_vars
= temp_vars
;
688 var idx_decl
= new
CCodeDeclaration ("int");
689 idx_decl
.add_declarator (new
CCodeVariableDeclarator ("i"));
690 block
.add_statement (idx_decl
);
692 var loop_body
= new
CCodeBlock ();
693 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
))));
695 var cfor
= new
CCodeForStatement (new
CCodeBinaryExpression (CCodeBinaryOperator
.LESS_THAN
, new
CCodeIdentifier ("i"), new
CCodeConstant ("%d".printf (array_type
.length
))), loop_body
);
696 cfor
.add_initializer (new
CCodeAssignment (new
CCodeIdentifier ("i"), new
CCodeConstant ("0")));
697 cfor
.add_iterator (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, new
CCodeIdentifier ("i")));
698 block
.add_statement (cfor
);
700 var cfrag
= new
CCodeFragment ();
701 append_temp_decl (cfrag
, temp_vars
);
702 block
.add_statement (cfrag
);
703 temp_vars
= old_temp_vars
;
705 source_declarations
.add_include ("string.h");
707 var dup_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("memcpy"));
708 dup_call
.add_argument (new
CCodeIdentifier ("dest"));
709 dup_call
.add_argument (new
CCodeIdentifier ("self"));
711 var sizeof_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
712 sizeof_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
713 dup_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("%d".printf (array_type
.length
)), sizeof_call
));
715 block
.add_statement (new
CCodeExpressionStatement (dup_call
));
720 source_declarations
.add_type_member_declaration (function
.copy ());
722 function
.block
= block
;
723 source_type_member_definition
.append (function
);
728 string generate_array_add_wrapper (ArrayType array_type
) {
729 string add_func
= "_vala_array_add%d".printf (++next_array_add_id
);
731 if (!add_wrapper (add_func
)) {
732 // wrapper already defined
738 var function
= new
CCodeFunction (add_func
, "void");
739 function
.modifiers
= CCodeModifiers
.STATIC
;
741 function
.add_parameter (new
CCodeFormalParameter ("array", array_type
.get_cname () + "*"));
742 function
.add_parameter (new
CCodeFormalParameter ("length", "int*"));
743 function
.add_parameter (new
CCodeFormalParameter ("size", "int*"));
745 string typename
= array_type
.element_type
.get_cname ();
746 CCodeExpression value
= new
CCodeIdentifier ("value");
747 if (array_type
.element_type
.is_real_struct_type ()) {
748 if (!array_type
.element_type
.nullable
|| !array_type
.element_type
.value_owned
) {
749 typename
= "const " + typename
;
751 if (!array_type
.element_type
.nullable
) {
753 value
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, value
);
756 function
.add_parameter (new
CCodeFormalParameter ("value", typename
));
758 var array
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("array"));
759 var length
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("length"));
760 var size
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("size"));
764 var block
= new
CCodeBlock ();
766 var renew_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_renew"));
767 renew_call
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
768 renew_call
.add_argument (array
);
769 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
770 // NULL terminate array
771 renew_call
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, size
, new
CCodeConstant ("1")));
773 renew_call
.add_argument (size
);
776 var resize_block
= new
CCodeBlock ();
777 resize_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (size
, new
CCodeConditionalExpression (size
, new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, new
CCodeConstant ("2"), size
), new
CCodeConstant ("4")))));
778 resize_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (array
, renew_call
)));
780 var csizecheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, length
, size
);
781 block
.add_statement (new
CCodeIfStatement (csizecheck
, resize_block
));
783 block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeElementAccess (array
, new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, length
)), value
)));
785 if (array_type
.element_type
.is_reference_type_or_type_parameter ()) {
786 // NULL terminate array
787 block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeElementAccess (array
, length
), new
CCodeConstant ("NULL"))));
792 source_declarations
.add_type_member_declaration (function
.copy ());
794 function
.block
= block
;
795 source_type_member_definition
.append (function
);
800 public override void visit_method_call (MethodCall expr
) {
801 base.visit_method_call (expr
);
803 var ccall
= expr
.ccodenode as CCodeFunctionCall
;
808 var cid
= ccall
.call as CCodeIdentifier
;
809 if (cid
== null || cid
.name
!= "g_array_index") {
813 // insert type argument in calls to g_array_index macro
815 var ma
= (MemberAccess
) expr
.call
;
816 var element_type
= ma
.inner
.value_type
.get_type_arguments ().get (0);
818 ccall
.insert_argument (1, new
CCodeIdentifier (element_type
.get_cname ()));
821 bool is_array_add (Assignment assignment
) {
822 var binary
= assignment
.right as BinaryExpression
;
823 if (binary
!= null && binary
.left
.value_type is ArrayType
) {
824 if (binary
.operator
== BinaryOperator
.PLUS
) {
825 if (assignment
.left
.symbol_reference
== binary
.left
.symbol_reference
) {
834 public override void visit_assignment (Assignment assignment
) {
835 if (!is_array_add (assignment
)) {
836 base.visit_assignment (assignment
);
840 var binary
= assignment
.right as BinaryExpression
;
842 var array
= binary
.left
;
843 var array_type
= (ArrayType
) array
.value_type
;
844 var element
= binary
.right
;
846 array
.accept (codegen
);
847 element
.target_type
= array_type
.element_type
.copy ();
848 element
.accept (codegen
);
850 var value_param
= new
FormalParameter ("value", element
.target_type
);
852 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (generate_array_add_wrapper (array_type
)));
853 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, (CCodeExpression
) array
.ccodenode
));
854 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_length_cexpression (array
)));
855 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_size_cexpression (array
)));
856 ccall
.add_argument (handle_struct_argument (value_param
, element
, (CCodeExpression
) element
.ccodenode
));
858 assignment
.ccodenode
= ccall
;
861 public override void generate_parameter (FormalParameter param
, CCodeDeclarationSpace decl_space
, Map
<int,CCodeFormalParameter
> cparam_map
, Map
<int,CCodeExpression
>? carg_map
) {
862 if (!(param
.parameter_type is ArrayType
)) {
863 base.generate_parameter (param
, decl_space
, cparam_map
, carg_map
);
867 string ctypename
= param
.parameter_type
.get_cname ();
869 if (param
.direction
!= ParameterDirection
.IN
) {
873 param
.ccodenode
= new
CCodeFormalParameter (get_variable_cname (param
.name
), ctypename
);
875 var array_type
= (ArrayType
) param
.parameter_type
;
877 generate_type_declaration (array_type
.element_type
, decl_space
);
879 cparam_map
.set (get_param_pos (param
.cparameter_position
), (CCodeFormalParameter
) param
.ccodenode
);
880 if (carg_map
!= null) {
881 carg_map
.set (get_param_pos (param
.cparameter_position
), get_variable_cexpression (param
.name
));
884 if (!param
.no_array_length
) {
885 var length_ctype
= "int";
886 if (param
.direction
!= ParameterDirection
.IN
) {
887 length_ctype
= "int*";
890 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
891 var cparam
= new
CCodeFormalParameter (head
.get_array_length_cname (get_variable_cname (param
.name
), dim
), length_ctype
);
892 cparam_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), cparam
);
893 if (carg_map
!= null) {
894 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), get_variable_cexpression (cparam
.name
));