valacodegenerator.vala 73.7 KB
Newer Older
1 2
/* valacodegenerator.vala
 *
3
 * Copyright (C) 2006-2007  Jürg Billeter, Raffaele Sandrini
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
21
 *	Raffaele Sandrini <rasa@gmx.ch>
22 23 24 25
 */

using GLib;

26 27 28 29 30 31 32 33 34
/**
 * Code visitor generating C Code.
 */
public class Vala.CodeGenerator : CodeVisitor {
	/**
	 * Specifies whether automatic memory management is active.
	 */
	public bool memory_management { get; set; }
	
35 36
	private CodeContext context;
	
37
	Symbol root_symbol;
38 39
	Symbol current_symbol;
	Symbol current_type_symbol;
40
	Class current_class;
41
	Method current_method;
42
	TypeReference current_return_type;
43 44 45 46 47 48 49 50

	CCodeFragment header_begin;
	CCodeFragment header_type_declaration;
	CCodeFragment header_type_definition;
	CCodeFragment header_type_member_declaration;
	CCodeFragment source_begin;
	CCodeFragment source_include_directives;
	CCodeFragment source_type_member_declaration;
51
	CCodeFragment source_signal_marshaller_declaration;
52
	CCodeFragment source_type_member_definition;
53 54
	CCodeFragment instance_init_fragment;
	CCodeFragment instance_dispose_fragment;
55
	CCodeFragment source_signal_marshaller_definition;
56
	CCodeFragment module_init_fragment;
57 58 59 60 61 62 63 64 65 66 67 68 69
	
	CCodeStruct instance_struct;
	CCodeStruct type_struct;
	CCodeStruct instance_priv_struct;
	CCodeEnum prop_enum;
	CCodeEnum cenum;
	CCodeFunction function;
	CCodeBlock block;
	
	/* all temporary variables */
	List<VariableDeclarator> temp_vars;
	/* temporary variables that own their content */
	List<VariableDeclarator> temp_ref_vars;
70 71 72 73
	/* cache to check whether a certain marshaller has been created yet */
	HashTable<string,bool> user_marshal_list;
	/* (constant) hash table with all predefined marshallers */
	HashTable<string,bool> predefined_marshal_list;
74 75
	/* (constant) hash table with all C keywords */
	HashTable<string,bool> c_keywords;
76 77
	
	private int next_temp_var_id = 0;
78
	private bool in_creation_method = false;
79

80
	TypeReference bool_type;
81 82 83 84
	TypeReference char_type;
	TypeReference unichar_type;
	TypeReference short_type;
	TypeReference ushort_type;
85
	TypeReference int_type;
86 87 88
	TypeReference uint_type;
	TypeReference long_type;
	TypeReference ulong_type;
89 90
	TypeReference int64_type;
	TypeReference uint64_type;
91
	TypeReference string_type;
92 93
	TypeReference float_type;
	TypeReference double_type;
94 95
	DataType list_type;
	DataType slist_type;
96
	TypeReference mutex_type;
97 98 99 100
	DataType type_module_type;

	private bool in_plugin = false;
	private string module_init_param_name;
101 102
	
	private bool string_h_needed;
103

104
	public CodeGenerator (bool manage_memory = true) {
105
		memory_management = manage_memory;
106 107 108
	}
	
	construct {
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
		predefined_marshal_list = new HashTable (str_hash, str_equal);
		predefined_marshal_list.insert ("VOID:VOID", true);
		predefined_marshal_list.insert ("VOID:BOOLEAN", true);
		predefined_marshal_list.insert ("VOID:CHAR", true);
		predefined_marshal_list.insert ("VOID:UCHAR", true);
		predefined_marshal_list.insert ("VOID:INT", true);
		predefined_marshal_list.insert ("VOID:UINT", true);
		predefined_marshal_list.insert ("VOID:LONG", true);
		predefined_marshal_list.insert ("VOID:ULONG", true);
		predefined_marshal_list.insert ("VOID:ENUM", true);
		predefined_marshal_list.insert ("VOID:FLAGS", true);
		predefined_marshal_list.insert ("VOID:FLOAT", true);
		predefined_marshal_list.insert ("VOID:DOUBLE", true);
		predefined_marshal_list.insert ("VOID:STRING", true);
		predefined_marshal_list.insert ("VOID:POINTER", true);
		predefined_marshal_list.insert ("VOID:OBJECT", true);
		predefined_marshal_list.insert ("STRING:OBJECT,POINTER", true);
		predefined_marshal_list.insert ("VOID:UINT,POINTER", true);
		predefined_marshal_list.insert ("BOOLEAN:FLAGS", true);
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171

		c_keywords = new HashTable (str_hash, str_equal);

		// C99 keywords
		c_keywords.insert ("_Bool", true);
		c_keywords.insert ("_Complex", true);
		c_keywords.insert ("_Imaginary", true);
		c_keywords.insert ("auto", true);
		c_keywords.insert ("break", true);
		c_keywords.insert ("case", true);
		c_keywords.insert ("char", true);
		c_keywords.insert ("const", true);
		c_keywords.insert ("continue", true);
		c_keywords.insert ("default", true);
		c_keywords.insert ("do", true);
		c_keywords.insert ("double", true);
		c_keywords.insert ("else", true);
		c_keywords.insert ("enum", true);
		c_keywords.insert ("extern", true);
		c_keywords.insert ("float", true);
		c_keywords.insert ("for", true);
		c_keywords.insert ("goto", true);
		c_keywords.insert ("if", true);
		c_keywords.insert ("inline", true);
		c_keywords.insert ("int", true);
		c_keywords.insert ("long", true);
		c_keywords.insert ("register", true);
		c_keywords.insert ("restrict", true);
		c_keywords.insert ("return", true);
		c_keywords.insert ("short", true);
		c_keywords.insert ("signed", true);
		c_keywords.insert ("sizeof", true);
		c_keywords.insert ("static", true);
		c_keywords.insert ("struct", true);
		c_keywords.insert ("switch", true);
		c_keywords.insert ("typedef", true);
		c_keywords.insert ("union", true);
		c_keywords.insert ("unsigned", true);
		c_keywords.insert ("void", true);
		c_keywords.insert ("volatile", true);
		c_keywords.insert ("while", true);

		// MSVC keywords
		c_keywords.insert ("cdecl", true);
172
	}
173

174 175 176 177 178 179
	/**
	 * Generate and emit C code for the specified code context.
	 *
	 * @param context a code context
	 */
	public void emit (CodeContext! context) {
180 181
		this.context = context;
	
182
		context.find_header_cycles ();
183 184 185 186

		root_symbol = context.get_root ();

		bool_type = new TypeReference ();
187
		bool_type.data_type = (DataType) root_symbol.lookup ("bool").node;
188

189 190 191 192 193 194 195 196 197 198 199 200
		char_type = new TypeReference ();
		char_type.data_type = (DataType) root_symbol.lookup ("char").node;

		unichar_type = new TypeReference ();
		unichar_type.data_type = (DataType) root_symbol.lookup ("unichar").node;

		short_type = new TypeReference ();
		short_type.data_type = (DataType) root_symbol.lookup ("short").node;
		
		ushort_type = new TypeReference ();
		ushort_type.data_type = (DataType) root_symbol.lookup ("ushort").node;

201 202
		int_type = new TypeReference ();
		int_type.data_type = (DataType) root_symbol.lookup ("int").node;
203 204 205 206 207 208 209 210 211
		
		uint_type = new TypeReference ();
		uint_type.data_type = (DataType) root_symbol.lookup ("uint").node;
		
		long_type = new TypeReference ();
		long_type.data_type = (DataType) root_symbol.lookup ("long").node;
		
		ulong_type = new TypeReference ();
		ulong_type.data_type = (DataType) root_symbol.lookup ("ulong").node;
212

213 214 215 216 217 218
		int64_type = new TypeReference ();
		int64_type.data_type = (DataType) root_symbol.lookup ("int64").node;
		
		uint64_type = new TypeReference ();
		uint64_type.data_type = (DataType) root_symbol.lookup ("uint64").node;
		
219 220 221 222 223 224
		float_type = new TypeReference ();
		float_type.data_type = (DataType) root_symbol.lookup ("float").node;

		double_type = new TypeReference ();
		double_type.data_type = (DataType) root_symbol.lookup ("double").node;

225
		string_type = new TypeReference ();
226
		string_type.data_type = (DataType) root_symbol.lookup ("string").node;
227 228 229 230 231

		var glib_ns = root_symbol.lookup ("GLib");
		
		list_type = (DataType) glib_ns.lookup ("List").node;
		slist_type = (DataType) glib_ns.lookup ("SList").node;
232 233 234
		
		mutex_type = new TypeReference ();
		mutex_type.data_type = (DataType) glib_ns.lookup ("Mutex").node;
235 236 237 238 239 240 241 242 243 244 245 246 247
		
		type_module_type = (DataType) glib_ns.lookup ("TypeModule").node;

		if (context.module_init_method != null) {
			module_init_fragment = new CCodeFragment ();
			foreach (FormalParameter parameter in context.module_init_method.get_parameters ()) {
				if (parameter.type_reference.data_type == type_module_type) {
					in_plugin = true;
					module_init_param_name = parameter.name;
					break;
				}
			}
		}
248 249 250 251 252 253
	
		/* we're only interested in non-pkg source files */
		var source_files = context.get_source_files ();
		foreach (SourceFile file in source_files) {
			if (!file.pkg) {
				file.accept (this);
254
			}
255
		}
256
	}
257

258 259 260 261
	public override void visit_namespace (Namespace! ns) {
		ns.accept_children (this);
	}

262
	public override void visit_enum (Enum! en) {
263
		cenum = new CCodeEnum (en.get_cname ());
264

265
		if (en.source_reference.comment != null) {
266
			header_type_definition.append (new CCodeComment (en.source_reference.comment));
267
		}
268
		header_type_definition.append (cenum);
269 270

		en.accept_children (this);
271
	}
272

273
	public override void visit_enum_value (EnumValue! ev) {
274 275 276 277 278 279 280 281
		string val;
		if (ev.value is LiteralExpression) {
			var lit = ((LiteralExpression) ev.value).literal;
			if (lit is IntegerLiteral) {
				val = ((IntegerLiteral) lit).value;
			}
		}
		cenum.add_value (ev.get_cname (), val);
282
	}
283

284
	public override void visit_flags (Flags! fl) {
285 286 287 288 289 290
		cenum = new CCodeEnum (fl.get_cname ());

		if (fl.source_reference.comment != null) {
			header_type_definition.append (new CCodeComment (fl.source_reference.comment));
		}
		header_type_definition.append (cenum);
291 292

		fl.accept_children (this);
293 294 295 296 297 298 299 300 301 302 303 304 305
	}

	public override void visit_flags_value (FlagsValue! fv) {
		string val;
		if (fv.value is LiteralExpression) {
			var lit = ((LiteralExpression) fv.value).literal;
			if (lit is IntegerLiteral) {
				val = ((IntegerLiteral) lit).value;
			}
		}
		cenum.add_value (fv.get_cname (), val);
	}

306 307 308
	public override void visit_callback (Callback! cb) {
		cb.accept_children (this);

309
		var cfundecl = new CCodeFunctionDeclarator (cb.get_cname ());
310 311 312
		foreach (FormalParameter param in cb.get_parameters ()) {
			cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode);
		}
313 314
		
		var ctypedef = new CCodeTypeDefinition (cb.return_type.get_cname (), cfundecl);
315
		
316
		if (cb.access != MemberAccessibility.PRIVATE) {
317 318 319
			header_type_declaration.append (ctypedef);
		} else {
			source_type_member_declaration.append (ctypedef);
320
		}
321
	}
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
	
	public override void visit_member (Member! m) {
		/* stuff meant for all lockable members */
		if (m is Lockable && ((Lockable)m).get_lock_used ()) {
			instance_priv_struct.add_field (mutex_type.get_cname (), get_symbol_lock_name (m.symbol));
			
			instance_init_fragment.append (
				new CCodeExpressionStatement (
					new CCodeAssignment (
						new CCodeMemberAccess.pointer (
							new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
							get_symbol_lock_name (m.symbol)),
					new CCodeFunctionCall (new CCodeIdentifier (((Struct)mutex_type.data_type).default_construction_method.get_cname ())))));
			
			var fc = new CCodeFunctionCall (new CCodeIdentifier ("VALA_FREE_CHECKED"));
			fc.add_argument (
				new CCodeMemberAccess.pointer (
					new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
					get_symbol_lock_name (m.symbol)));
			fc.add_argument (new CCodeIdentifier (mutex_type.data_type.get_free_function ()));
342 343 344
			if (instance_dispose_fragment != null) {
				instance_dispose_fragment.append (new CCodeExpressionStatement (fc));
			}
345 346
		}
	}
347

348
	public override void visit_constant (Constant! c) {
349 350
		c.accept_children (this);

351 352
		if (c.symbol.parent_symbol.node is DataType) {
			var t = (DataType) c.symbol.parent_symbol.node;
353
			var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ());
354
			var arr = "";
355
			if (c.type_reference.data_type is Array) {
356
				arr = "[]";
357
			}
358
			cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s%s".printf (c.get_cname (), arr), (CCodeExpression) c.initializer.ccodenode));
359
			cdecl.modifiers = CCodeModifiers.STATIC;
360
			
361
			if (c.access != MemberAccessibility.PRIVATE) {
362 363 364 365
				header_type_member_declaration.append (cdecl);
			} else {
				source_type_member_declaration.append (cdecl);
			}
366
		}
367 368 369
	}
	
	public override void visit_field (Field! f) {
370 371
		f.accept_children (this);

372
		CCodeExpression lhs = null;
373
		CCodeStruct st = null;
374
		
375
		if (f.access != MemberAccessibility.PRIVATE) {
376
			st = instance_struct;
377 378 379
			if (f.instance) {
				lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
			}
380 381
		} else if (f.access == MemberAccessibility.PRIVATE) {
			if (f.instance) {
382
				st = instance_priv_struct;
383
				lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
384 385 386
			} else {
				if (f.symbol.parent_symbol.node is DataType) {
					var t = (DataType) f.symbol.parent_symbol.node;
387
					var cdecl = new CCodeDeclaration (f.type_reference.get_cname ());
388
					var var_decl = new CCodeVariableDeclarator (f.get_cname ());
389 390
					if (f.initializer != null) {
						var_decl.initializer = (CCodeExpression) f.initializer.ccodenode;
Jürg Billeter's avatar
Jürg Billeter committed
391 392 393 394
					}
					cdecl.add_declarator (var_decl);
					cdecl.modifiers = CCodeModifiers.STATIC;
					source_type_member_declaration.append (cdecl);
395
				}
396
			}
397
		}
398

Jürg Billeter's avatar
Jürg Billeter committed
399 400 401 402 403 404 405 406 407
		if (f.instance)  {
			st.add_field (f.type_reference.get_cname (), f.get_cname ());
			if (f.type_reference.data_type is Array && !f.no_array_length) {
				// create fields to store array dimensions
				var arr = (Array) f.type_reference.data_type;
				
				for (int dim = 1; dim <= arr.rank; dim++) {
					var len_type = new TypeReference ();
					len_type.data_type = int_type.data_type;
408

Jürg Billeter's avatar
Jürg Billeter committed
409 410
					st.add_field (len_type.get_cname (), get_array_length_cname (f.name, dim));
				}
411
			}
Jürg Billeter's avatar
Jürg Billeter committed
412

Jürg Billeter's avatar
Jürg Billeter committed
413 414 415 416 417 418 419 420 421 422 423 424 425
			if (f.initializer != null) {
				instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, (CCodeExpression) f.initializer.ccodenode)));
				
				if (f.type_reference.data_type is Array && !f.no_array_length &&
				    f.initializer is ArrayCreationExpression) {
					var ma = new MemberAccess.simple (f.name);
					ma.symbol_reference = f.symbol;
					
					var array_len_lhs = get_array_length_cexpression (ma, 1);
					var sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
					var size = (Expression) sizes.data;
					instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (array_len_lhs, (CCodeExpression) size.ccodenode)));
				}
426
			}
427
			
Jürg Billeter's avatar
Jürg Billeter committed
428 429
			if (f.type_reference.takes_ownership && instance_dispose_fragment != null) {
				instance_dispose_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.type_reference)));
430
			}
431
		}
432
	}
433

434
	public override void visit_formal_parameter (FormalParameter! p) {
435 436
		p.accept_children (this);

437
		if (!p.ellipsis) {
438
			p.ccodenode = new CCodeFormalParameter (p.name, p.type_reference.get_cname (false, !p.type_reference.takes_ownership));
439
		}
440
	}
441

442 443 444
	public override void visit_property (Property! prop) {
		prop.accept_children (this);

445
		prop_enum.add_value (prop.get_upper_case_cname (), null);
446
	}
447

448
	public override void visit_property_accessor (PropertyAccessor! acc) {
449 450 451 452 453 454 455 456 457
		var prop = (Property) acc.symbol.parent_symbol.node;
		
		if (acc.readable) {
			current_return_type = prop.type_reference;
		} else {
			// void
			current_return_type = new TypeReference ();
		}

458
		acc.accept_children (this);
459 460

		current_return_type = null;
461 462 463

		var t = (DataType) prop.symbol.parent_symbol.node;

464
		var this_type = new TypeReference ();
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
		this_type.data_type = t;
		var cselfparam = new CCodeFormalParameter ("self", this_type.get_cname ());
		var cvalueparam = new CCodeFormalParameter ("value", prop.type_reference.get_cname (false, true));

		if (prop.is_abstract || prop.is_virtual) {
			if (acc.readable) {
				function = new CCodeFunction ("%s_get_%s".printf (t.get_lower_case_cname (null), prop.name), prop.type_reference.get_cname ());
			} else {
				function = new CCodeFunction ("%s_set_%s".printf (t.get_lower_case_cname (null), prop.name), "void");
			}
			function.add_parameter (cselfparam);
			if (acc.writable || acc.construction) {
				function.add_parameter (cvalueparam);
			}
			
			header_type_member_declaration.append (function.copy ());
			
			var block = new CCodeBlock ();
			function.block = block;

			if (acc.readable) {
				// declare temporary variable to save the property value
				var decl = new CCodeDeclaration (prop.type_reference.get_cname ());
				decl.add_declarator (new CCodeVariableDeclarator ("value"));
				block.add_statement (decl);
			
				var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
			
				var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
				ccast.add_argument (new CCodeIdentifier ("self"));
				ccall.add_argument (ccast);
				
				// property name is second argument of g_object_get
				ccall.add_argument (prop.get_canonical_cconstant ());

				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));

				ccall.add_argument (new CCodeConstant ("NULL"));
				
				block.add_statement (new CCodeExpressionStatement (ccall));
				block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
			} else {
				var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
			
				var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
				ccast.add_argument (new CCodeIdentifier ("self"));
				ccall.add_argument (ccast);
				
				// property name is second argument of g_object_set
				ccall.add_argument (prop.get_canonical_cconstant ());

				ccall.add_argument (new CCodeIdentifier ("value"));

				ccall.add_argument (new CCodeConstant ("NULL"));
				
				block.add_statement (new CCodeExpressionStatement (ccall));
			}

			source_type_member_definition.append (function);
524
		}
525

526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
		if (!prop.is_abstract) {
			bool is_virtual = prop.base_property != null || prop.base_interface_property != null;

			string prefix = t.get_lower_case_cname (null);
			if (is_virtual) {
				prefix += "_real";
			}
			if (acc.readable) {
				function = new CCodeFunction ("%s_get_%s".printf (prefix, prop.name), prop.type_reference.get_cname ());
			} else {
				function = new CCodeFunction ("%s_set_%s".printf (prefix, prop.name), "void");
			}
			if (is_virtual) {
				function.modifiers |= CCodeModifiers.STATIC;
			}
			function.add_parameter (cselfparam);
			if (acc.writable || acc.construction) {
				function.add_parameter (cvalueparam);
			}

			if (!is_virtual) {
				header_type_member_declaration.append (function.copy ());
			}
			
			if (acc.body != null) {
				function.block = (CCodeBlock) acc.body.ccodenode;

				function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
			}
			
			source_type_member_definition.append (function);
557 558
		}
	}
Jürg Billeter's avatar
Jürg Billeter committed
559

560 561 562
	public override void visit_constructor (Constructor! c) {
		c.accept_children (this);

563 564
		var cl = (Class) c.symbol.parent_symbol.node;
	
565
		function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
566 567
		function.modifiers = CCodeModifiers.STATIC;
		
568 569 570
		function.add_parameter (new CCodeFormalParameter ("type", "GType"));
		function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint"));
		function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
571 572
		
		source_type_member_declaration.append (function.copy ());
573 574


575
		var cblock = new CCodeBlock ();
576 577
		var cdecl = new CCodeDeclaration ("GObject *");
		cdecl.add_declarator (new CCodeVariableDeclarator ("obj"));
578
		cblock.add_statement (cdecl);
579

580 581
		cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
		cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
582
		cblock.add_statement (cdecl);
583

584 585
		cdecl = new CCodeDeclaration ("GObjectClass *");
		cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
586
		cblock.add_statement (cdecl);
587 588


589 590 591
		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek"));
		ccall.add_argument (new CCodeIdentifier (cl.get_upper_case_cname ("TYPE_")));
		var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
592
		ccast.add_argument (ccall);
593
		cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast)));
594

595 596 597
		ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
		ccall.add_argument (new CCodeIdentifier ("klass"));
		ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
598
		ccast.add_argument (ccall);
599
		cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
600

601
		
602 603 604 605 606
		ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
		ccall.add_argument (new CCodeIdentifier ("type"));
		ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
		ccall.add_argument (new CCodeIdentifier ("construct_properties"));
		cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall)));
607 608


609 610
		ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
		ccall.add_argument (new CCodeIdentifier ("obj"));
611
		
612 613
		cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
		cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
614 615
		
		cblock.add_statement (cdecl);
616

617 618 619

		cblock.add_statement (c.body.ccodenode);
		
620
		cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
621 622 623 624
		
		function.block = cblock;

		if (c.source_reference.comment != null) {
625
			source_type_member_definition.append (new CCodeComment (c.source_reference.comment));
626
		}
627 628
		source_type_member_definition.append (function);
	}
629

630 631 632 633
	public override void visit_destructor (Destructor! d) {
		d.accept_children (this);
	}

634 635 636
	public override void visit_begin_block (Block! b) {
		current_symbol = b.symbol;
	}
637 638 639 640
	
	private void add_object_creation (CCodeBlock! b) {
		var cl = (Class) current_type_symbol.node;
	
641 642 643 644
		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
		ccall.add_argument (new CCodeConstant (cl.get_type_id ()));
		ccall.add_argument (new CCodeConstant ("__params_it - __params"));
		ccall.add_argument (new CCodeConstant ("__params"));
645
		
646
		var cdecl = new CCodeVariableDeclarator ("self");
647 648
		cdecl.initializer = ccall;
		
649
		var cdeclaration = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
650 651 652 653
		cdeclaration.add_declarator (cdecl);
		
		b.add_statement (cdeclaration);
	}
654 655 656 657 658 659

	public override void visit_end_block (Block! b) {
		var local_vars = b.get_local_variables ();
		foreach (VariableDeclarator decl in local_vars) {
			decl.symbol.active = false;
		}
660
		
661
		var cblock = new CCodeBlock ();
662
		
663 664 665
		foreach (Statement stmt in b.get_statements ()) {
			var src = stmt.source_reference;
			if (src != null && src.comment != null) {
666
				cblock.add_statement (new CCodeComment (src.comment));
667
			}
668
			
669
			if (stmt.ccodenode is CCodeFragment) {
670
				foreach (CCodeStatement cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
671
					cblock.add_statement (cstmt);
672
				}
673 674
			} else {
				cblock.add_statement ((CCodeStatement) stmt.ccodenode);
675
			}
676 677 678 679
		}
		
		if (memory_management) {
			foreach (VariableDeclarator decl in local_vars) {
680
				if (decl.type_reference.takes_ownership) {
681
					cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (decl.name)), decl.type_reference)));
682 683
				}
			}
684
		}
685 686
		
		b.ccodenode = cblock;
687

688 689
		current_symbol = current_symbol.parent_symbol;
	}
690

691 692 693
	public override void visit_empty_statement (EmptyStatement! stmt) {
		stmt.ccodenode = new CCodeEmptyStatement ();
	}
694 695 696 697 698 699 700 701 702 703
	
	private bool struct_has_instance_fields (Struct! st) {
		foreach (Field f in st.get_fields ()) {
			if (f.instance) {
				return true;
			}
		}
		
		return false;
	}
704

705 706 707 708 709 710
	public override void visit_declaration_statement (DeclarationStatement! stmt) {
		/* split declaration statement as var declarators
		 * might have different types */
	
		var cfrag = new CCodeFragment ();
		
711
		foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) {
712
			var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (false, !decl.type_reference.takes_ownership));
713 714
		
			cdecl.add_declarator ((CCodeVariableDeclarator) decl.ccodenode);
715

716
			cfrag.append (cdecl);
717
			
718
			/* try to initialize uninitialized variables */
719
			if (decl.initializer == null && decl.type_reference.data_type is Struct) {
720 721 722 723 724 725 726 727
				if (decl.type_reference.data_type.is_reference_type ()) {
					((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant ("NULL");
				} else if (decl.type_reference.data_type.get_default_value () != null) {
					((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant (decl.type_reference.data_type.get_default_value ());
				} else if (decl.type_reference.data_type is Struct &&
				           struct_has_instance_fields ((Struct) decl.type_reference.data_type)) {
					var st = (Struct) decl.type_reference.data_type;

728 729
					/* memset needs string.h */
					string_h_needed = true;
730

731
					var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
732
					czero.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (get_variable_cname (decl.name))));
733 734
					czero.add_argument (new CCodeConstant ("0"));
					czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (decl.type_reference.get_cname ())));
735

736
					cfrag.append (new CCodeExpressionStatement (czero));
737 738
				} else {
					Report.warning (decl.source_reference, "unable to initialize a variable of type `%s'".printf (decl.type_reference.data_type.symbol.get_full_name ()));
739 740
				}
			}
741
		}
742 743
		
		stmt.ccodenode = cfrag;
744

745
		foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) {
746
			if (decl.initializer != null) {
747
				create_temp_decl (stmt, decl.initializer.temp_vars);
748 749
			}
		}
750 751 752

		create_temp_decl (stmt, temp_vars);
		temp_vars = null;
753
	}
754

755 756 757 758 759 760 761 762
	private string! get_variable_cname (string! name) {
		if (c_keywords.lookup (name)) {
			return name + "_";
		} else {
			return name;
		}
	}

763
	public override void visit_variable_declarator (VariableDeclarator! decl) {
764 765 766 767 768 769 770 771 772 773 774 775 776
		if (decl.type_reference.data_type is Array) {
			// create variables to store array dimensions
			var arr = (Array) decl.type_reference.data_type;
			
			for (int dim = 1; dim <= arr.rank; dim++) {
				var len_decl = new VariableDeclarator (get_array_length_cname (decl.name, dim));
				len_decl.type_reference = new TypeReference ();
				len_decl.type_reference.data_type = int_type.data_type;

				temp_vars.prepend (len_decl);
			}
		}
	
777 778 779 780
		CCodeExpression rhs = null;
		if (decl.initializer != null) {
			rhs = (CCodeExpression) decl.initializer.ccodenode;
			
781 782 783 784
			if (decl.type_reference.data_type != null
			    && decl.initializer.static_type.data_type != null
			    && decl.type_reference.data_type.is_reference_type ()
			    && decl.initializer.static_type.data_type != decl.type_reference.data_type) {
785
				// FIXME: use C cast if debugging disabled
786
				rhs = new InstanceCast (rhs, decl.type_reference.data_type);
787
			}
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803

			if (decl.type_reference.data_type is Array) {
				var ccomma = new CCodeCommaExpression ();
				
				var temp_decl = get_temp_variable_declarator (decl.type_reference);
				temp_vars.prepend (temp_decl);
				ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs));
				
				var lhs_array_len = new CCodeIdentifier (get_array_length_cname (decl.name, 1));
				var rhs_array_len = get_array_length_cexpression (decl.initializer, 1);
				ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
				
				ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
				
				rhs = ccomma;
			}
804
		} else if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) {
805
			rhs = new CCodeConstant ("NULL");
806
		}
807
			
808
		decl.ccodenode = new CCodeVariableDeclarator.with_initializer (get_variable_cname (decl.name), rhs);
809 810 811 812

		decl.symbol.active = true;
	}

813 814 815 816 817 818 819 820 821
	public override void visit_end_initializer_list (InitializerList! list) {
		if (list.expected_type != null && list.expected_type.data_type is Array) {
			/* TODO */
		} else {
			var clist = new CCodeInitializerList ();
			foreach (Expression expr in list.get_initializers ()) {
				clist.append ((CCodeExpression) expr.ccodenode);
			}
			list.ccodenode = clist;
822
		}
823 824
	}
	
825
	private VariableDeclarator get_temp_variable_declarator (TypeReference! type, bool takes_ownership = true) {
826
		var decl = new VariableDeclarator ("__temp%d".printf (next_temp_var_id));
827
		decl.type_reference = type.copy ();
828
		decl.type_reference.is_ref = false;
829
		decl.type_reference.is_out = false;
830
		decl.type_reference.takes_ownership = takes_ownership;
831
		
832 833 834 835
		next_temp_var_id++;
		
		return decl;
	}
836 837 838 839 840 841 842 843 844 845

	private CCodeExpression get_destroy_func_expression (TypeReference! type) {
		if (type.data_type != null) {
			string unref_function;
			if (type.data_type.is_reference_counting ()) {
				unref_function = type.data_type.get_unref_function ();
			} else {
				unref_function = type.data_type.get_free_function ();
			}
			return new CCodeIdentifier (unref_function);
846 847 848 849
		} else if (type.type_parameter != null && current_class != null) {
			string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
			return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
		} else {
850 851 852 853
			return new CCodeConstant ("NULL");
		}
	}

854
	private CCodeExpression get_unref_expression (CCodeExpression! cvar, TypeReference! type) {
855 856 857 858 859 860
		/* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
		
		/* can be simplified to
		 * foo = (unref (foo), NULL)
		 * if foo is of static type non-null
		 */
861

862 863 864 865
		if (type.is_null) {
			return new CCodeConstant ("NULL");
		}

866
		var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
867 868 869 870 871 872 873 874 875
		if (type.data_type == null) {
			if (current_class == null) {
				return new CCodeConstant ("NULL");
			}

			// unref functions are optional for type parameters
			var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
			cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
		}
876

877
		var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
878
		ccall.add_argument (cvar);
879
		
880 881
		/* set freed references to NULL to prevent further use */
		var ccomma = new CCodeCommaExpression ();
882

883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
		// TODO cleanup
		if (type.data_type != null && !type.data_type.is_reference_counting ()) {
			string unref_function = type.data_type.get_free_function ();
			if (unref_function == "g_list_free") {
				bool is_ref = false;
				bool is_class = false;
				bool is_interface = false;

				foreach (TypeReference type_arg in type.get_type_arguments ()) {
					is_ref |= type_arg.takes_ownership;
					is_class |= type_arg.data_type is Class;
					is_interface |= type_arg.data_type is Interface;
				}
				
				if (is_ref) {
					var cunrefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
					cunrefcall.add_argument (cvar);
					if (is_class || is_interface) {
						cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_unref"));
					} else {
						cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_free"));
					}
					cunrefcall.add_argument (new CCodeConstant ("NULL"));
					ccomma.append_expression (cunrefcall);
907
				}
908 909
			} else if (unref_function == "g_string_free") {
				ccall.add_argument (new CCodeConstant ("TRUE"));
910
			}
911 912
		}
		
913
		ccomma.append_expression (ccall);
914
		ccomma.append_expression (new CCodeConstant ("NULL"));
915
		
916
		var cassign = new CCodeAssignment (cvar, ccomma);
917 918 919 920 921 922

		// g_free (NULL) is allowed
		if (type.non_null || (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free")) {
			return new CCodeParenthesizedExpression (cassign);
		}

923
		return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), new CCodeParenthesizedExpression (cassign));
924 925 926 927
	}
	
	public override void visit_end_full_expression (Expression! expr) {
		if (!memory_management) {
928 929
			temp_vars = null;
			temp_ref_vars = null;
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961
			return;
		}
	
		/* expr is a full expression, i.e. an initializer, the
		 * expression in an expression statement, the controlling
		 * expression in if, while, for, or foreach statements
		 *
		 * we unref temporary variables at the end of a full
		 * expression
		 */
		
		/* can't automatically deep copy lists yet, so do it
		 * manually for now
		 * replace with
		 * expr.temp_vars = temp_vars;
		 * when deep list copying works
		 */
		expr.temp_vars = null;
		foreach (VariableDeclarator decl1 in temp_vars) {
			expr.temp_vars.append (decl1);
		}
		temp_vars = null;

		if (temp_ref_vars == null) {
			/* nothing to do without temporary variables */
			return;
		}
		
		var full_expr_decl = get_temp_variable_declarator (expr.static_type);
		expr.temp_vars.append (full_expr_decl);
		
		var expr_list = new CCodeCommaExpression ();
962
		expr_list.append_expression (new CCodeAssignment (new CCodeIdentifier (full_expr_decl.name), (CCodeExpression) expr.ccodenode));
963 964
		
		foreach (VariableDeclarator decl in temp_ref_vars) {
965
			expr_list.append_expression (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference));
966 967
		}
		
968
		expr_list.append_expression (new CCodeIdentifier (full_expr_decl.name));
969 970 971 972 973 974 975 976
		
		expr.ccodenode = expr_list;
		
		temp_ref_vars = null;
	}
	
	private void append_temp_decl (CCodeFragment! cfrag, List<VariableDeclarator> temp_vars) {
		foreach (VariableDeclarator decl in temp_vars) {
977
			var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (true, !decl.type_reference.takes_ownership));
978
		
979
			var vardecl = new CCodeVariableDeclarator (decl.name);
980 981
			cdecl.add_declarator (vardecl);
			
982
			if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) {
983
				vardecl.initializer = new CCodeConstant ("NULL");
984
			}
985
			
986
			cfrag.append (cdecl);
987
		}
988
	}
989

990
	public override void visit_expression_statement (ExpressionStatement! stmt) {
991
		stmt.ccodenode = new CCodeExpressionStatement ((CCodeExpression) stmt.expression.ccodenode);
992 993 994
		
		/* free temporary objects */
		if (!memory_management) {
995
			temp_vars = null;
996
			temp_ref_vars = null;
997
			return;
998 999
		}
		
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
		if (temp_vars == null) {
			/* nothing to do without temporary variables */
			return;
		}
		
		var cfrag = new CCodeFragment ();
		append_temp_decl (cfrag, temp_vars);
		
		cfrag.append (stmt.ccodenode);
		
		foreach (VariableDeclarator decl in temp_ref_vars) {
1011
			cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)));
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
		}
		
		stmt.ccodenode = cfrag;
		
		temp_vars = null;
		temp_ref_vars = null;
	}
	
	private void create_temp_decl (Statement! stmt, List<VariableDeclarator> temp_vars) {
		/* declare temporary variables */
		
		if (temp_vars == null) {
			/* nothing to do without temporary variables */
			return;
1026
		}
1027 1028 1029 1030 1031 1032 1033 1034
		
		var cfrag = new CCodeFragment ();
		append_temp_decl (cfrag, temp_vars);
		
		cfrag.append (stmt.ccodenode);
		
		stmt.ccodenode = cfrag;
	}
1035

1036 1037
	public override void visit_if_statement (IfStatement! stmt) {
		if (stmt.false_statement != null) {
1038
			stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
1039
		} else {
1040
			stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
1041
		}
1042 1043 1044
		
		create_temp_decl (stmt, stmt.condition.temp_vars);
	}
1045

1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
	public override void visit_switch_statement (SwitchStatement! stmt) {
		// we need a temporary variable to save the property value
		var temp_decl = get_temp_variable_declarator (stmt.expression.static_type);
		stmt.expression.temp_vars.prepend (temp_decl);

		var ctemp = new CCodeIdentifier (temp_decl.name);
		
		var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode);
		
		var cswitchblock = new CCodeFragment ();
		cswitchblock.append (new CCodeExpressionStatement (cinit));
		stmt.ccodenode = cswitchblock;

		create_temp_decl (stmt, stmt.expression.temp_vars);

1061
		List<weak Statement> default_statements = null;
1062 1063
		
		// generate nested if statements		
1064
		CCodeStatement ctopstmt = null;
1065
		CCodeIfStatement coldif = null;
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
		foreach (SwitchSection section in stmt.get_sections ()) {
			if (section.has_default_label ()) {
				default_statements = section.get_statements ();
			} else {
				CCodeBinaryExpression cor = null;
				foreach (SwitchLabel label in section.get_labels ()) {
					var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, (CCodeExpression) label.expression.ccodenode);
					if (cor == null) {
						cor = ccmp;
					} else {
						cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
					}
				}
				
				var cblock = new CCodeBlock ();
				foreach (Statement body_stmt in section.get_statements ()) {
1082 1083 1084 1085 1086 1087 1088
					if (body_stmt.ccodenode is CCodeFragment) {
						foreach (CCodeStatement cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) {
							cblock.add_statement (cstmt);
						}
					} else {
						cblock.add_statement ((CCodeStatement) body_stmt.ccodenode);
					}
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
				}
				
				var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
				
				var cif = new CCodeIfStatement (cor, cdo);
				if (coldif != null) {
					coldif.false_statement = cif;
				} else {
					ctopstmt = cif;
				}
				coldif = cif;
			}
		}
		
		if (default_statements != null) {
			var cblock = new CCodeBlock ();
			foreach (Statement body_stmt in default_statements) {
				cblock.add_statement ((CCodeStatement) body_stmt.ccodenode);
			}
			
			var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));

			if (coldif == null) {
				// there is only one section and that section
				// contains a default label
				ctopstmt = cdo;
			} else {
				coldif.false_statement = cdo;
			}
		}
		
		cswitchblock.append (ctopstmt);
	}

1123
	public override void visit_while_statement (WhileStatement! stmt) {
1124
		stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
1125 1126 1127 1128
		
		create_temp_decl (stmt, stmt.condition.temp_vars);
	}

1129 1130 1131 1132 1133 1134
	public override void visit_do_statement (DoStatement! stmt) {
		stmt.ccodenode = new CCodeDoStatement ((CCodeStatement) stmt.body.ccodenode, (CCodeExpression) stmt.condition.ccodenode);
		
		create_temp_decl (stmt, stmt.condition.temp_vars);
	}

1135
	public override void visit_for_statement (ForStatement! stmt) {
1136
		var cfor = new CCodeForStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
1137
		stmt.ccodenode = cfor;
1138
		
1139
		foreach (Expression init_expr in stmt.get_initializer ()) {
1140
			cfor.add_initializer ((CCodeExpression) init_expr.ccodenode);
1141
			create_temp_decl (stmt, init_expr.temp_vars);
Jürg Billeter's avatar
Jürg Billeter committed
1142
		}
1143
		
1144
		foreach (Expression it_expr in stmt.get_iterator ()) {
1145
			cfor.add_iterator ((CCodeExpression) it_expr.ccodenode);
1146
			create_temp_decl (stmt, it_expr.temp_vars);
1147
		}
1148

1149 1150
		create_temp_decl (stmt, stmt.condition.temp_vars);
	}
Jürg Billeter's avatar
Jürg Billeter committed
1151

1152 1153
	public override void visit_end_foreach_statement (ForeachStatement! stmt) {
		var cblock = new CCodeBlock ();
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
		CCodeForStatement cfor;
		VariableDeclarator collection_backup = get_temp_variable_declarator (stmt.collection.static_type);
		
		stmt.collection.temp_vars.prepend (collection_backup);
		var cfrag = new CCodeFragment ();
		append_temp_decl (cfrag, stmt.collection.temp_vars);
		cblock.add_statement (cfrag);
		cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode)));
		
		stmt.ccodenode = cblock;
1164
		
1165
		if (stmt.collection.static_type.data_type is Array) {