GIR writer: Generate correct GIR namespace name and version
[vala-lang.git] / codegen / valaccodearraymodule.vala
blobee113710334f12dcd3205b22ccfce80060a3b63d
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using Gee;
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) {
32 base (codegen, 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 ()) {
37 if (rank > 1) {
38 append_initializer_list (ce, name_cnode, (InitializerList) e, rank - 1, ref i);
39 } else {
40 ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
41 i++;
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);
56 int i = 0;
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);
64 expr.ccodenode = ce;
66 return;
69 var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
70 gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ()));
71 bool first = true;
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);
88 if (first) {
89 cexpr = csize;
90 first = false;
91 } else {
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);
107 int i = 0;
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);
117 expr.ccodenode = ce;
118 } else {
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
135 if (dim == -1) {
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));
141 return cexpr;
142 } else {
143 dim = 1;
147 bool is_out = false;
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;
153 is_out = true;
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);
176 return len_call;
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);
183 if (is_out) {
184 // passing array as out/ref
185 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
186 } else {
187 return 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));
193 if (is_out) {
194 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
195 } else {
196 return 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");
215 } else {
216 inst = typed_inst;
218 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
219 carray_expr = new CCodeMemberAccess.pointer (inst, array_cname);
220 } else {
221 carray_expr = new CCodeMemberAccess (inst, array_cname);
223 } else {
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);
230 return len_call;
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);
242 string length_cname;
243 if (field.has_array_length_cname) {
244 length_cname = field.get_array_length_cname ();
245 } else {
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");
253 } else {
254 inst = typed_inst;
256 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
257 length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
258 } else {
259 length_expr = new CCodeMemberAccess (inst, length_cname);
261 } else {
262 length_expr = new CCodeIdentifier (get_array_length_cname (field.get_cname (), dim));
265 if (is_out) {
266 return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
267 } else {
268 return 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 ()));
275 return ccall;
277 } else if (array_expr is NullLiteral) {
278 return new CCodeConstant ("0");
281 if (!is_out) {
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");
289 } else {
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");
318 } else {
319 inst = typed_inst;
321 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
322 size_expr = new CCodeMemberAccess.pointer (inst, size_cname);
323 } else {
324 size_expr = new CCodeMemberAccess (inst, size_cname);
326 } else {
327 size_expr = new CCodeIdentifier (get_array_size_cname (field.get_cname ()));
330 return size_expr;
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;
366 } else {
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"))));
394 return cfor;
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")));
525 fun.block = block;
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);
552 return ccomma;
553 } else {
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));
565 } else {
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"));
587 return ccall;
588 } else {
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
598 return dup_func;
601 // declaration
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"));
610 // definition
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;
644 } else {
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));
655 // append to file
657 source_declarations.add_type_member_declaration (function.copy ());
659 function.block = block;
660 source_type_member_definition.append (function);
662 return dup_func;
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
670 return dup_func;
673 // declaration
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 () + "*"));
681 // definition
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;
704 } else {
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));
718 // append to file
720 source_declarations.add_type_member_declaration (function.copy ());
722 function.block = block;
723 source_type_member_definition.append (function);
725 return dup_func;
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
733 return add_func;
736 // declaration
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) {
752 typename += "*";
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"));
762 // definition
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")));
772 } else {
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"))));
790 // append to file
792 source_declarations.add_type_member_declaration (function.copy ());
794 function.block = block;
795 source_type_member_definition.append (function);
797 return add_func;
800 public override void visit_method_call (MethodCall expr) {
801 base.visit_method_call (expr);
803 var ccall = expr.ccodenode as CCodeFunctionCall;
804 if (ccall == null) {
805 return;
808 var cid = ccall.call as CCodeIdentifier;
809 if (cid == null || cid.name != "g_array_index") {
810 return;
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) {
826 return true;
831 return false;
834 public override void visit_assignment (Assignment assignment) {
835 if (!is_array_add (assignment)) {
836 base.visit_assignment (assignment);
837 return;
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);
864 return;
867 string ctypename = param.parameter_type.get_cname ();
869 if (param.direction != ParameterDirection.IN) {
870 ctypename += "*";
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));