valaccodestructmodule.vala 10.8 KB
Newer Older
Jürg Billeter's avatar
Jürg Billeter committed
1
/* valaccodestructmodule.vala
2
 *
3 4
 * Copyright (C) 2006-2009  Jürg Billeter
 * Copyright (C) 2006-2008  Raffaele Sandrini
5 6 7 8
 *
 * 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
9
 * version 2.1 of the License, or (at your option) any later version.
10 11 12 13 14 15 16 17 18 19 20 21

 * 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>
22
 *	Raffaele Sandrini <raffaele@sandrini.ch>
23 24 25 26
 */

using GLib;

27
public abstract class Vala.CCodeStructModule : CCodeBaseModule {
28
	public override void generate_struct_declaration (Struct st, CCodeFile decl_space) {
29
		if (add_symbol_declaration (decl_space, st, get_ccode_name (st))) {
30
			return;
31 32
		}

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
		if (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ()) {
			if (st.base_struct != null) {
				generate_struct_declaration (st.base_struct, decl_space);
				decl_space.add_type_declaration (new CCodeTypeDefinition (get_ccode_name (st.base_struct), new CCodeVariableDeclarator (get_ccode_name (st))));
			} else {
				string typename = null;
				if (st.is_boolean_type ()) {
					// typedef for boolean types
					decl_space.add_include ("stdbool.h");
					typename = "bool";
				} else if (st.is_integer_type ()) {
					// typedef for integral types
					decl_space.add_include ("stdint.h");
					typename = "%sint%d_t".printf (st.signed ? "" : "u", st.width);
				} else if (st.is_floating_type ()) {
					// typedef for floating types
					typename = (st.width == 64 ? "double" : "float");
				}
				decl_space.add_type_declaration (new CCodeTypeDefinition (typename, new CCodeVariableDeclarator (get_ccode_name (st))));
			}
53 54 55
			return;
		}

Jürg Billeter's avatar
Jürg Billeter committed
56 57 58 59 60 61 62 63
		if (get_ccode_has_type_id (st)) {
			decl_space.add_type_declaration (new CCodeNewline ());
			var macro = "(%s_get_type ())".printf (get_ccode_lower_case_name (st, null));
			decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (st), macro));

			var type_fun = new StructRegisterFunction (st, context);
			type_fun.init_from_type (false, true);
			decl_space.add_type_member_declaration (type_fun.get_declaration ());
64 65
		}

66
		var instance_struct = new CCodeStruct ("_%s".printf (get_ccode_name (st)));
67
		instance_struct.deprecated = st.deprecated;
68 69

		foreach (Field f in st.get_fields ()) {
70
			string field_ctype = get_ccode_name (f.variable_type);
71 72 73 74 75
			if (f.is_volatile) {
				field_ctype = "volatile " + field_ctype;
			}

			if (f.binding == MemberBinding.INSTANCE)  {
Jürg Billeter's avatar
Jürg Billeter committed
76
				generate_type_declaration (f.variable_type, decl_space);
77

78
				instance_struct.add_field (field_ctype, get_ccode_name (f) + get_ccode_declarator_suffix (f.variable_type), f.deprecated ? " G_GNUC_DEPRECATED" : null);
79
				if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
80
					// create fields to store array dimensions
Jürg Billeter's avatar
Jürg Billeter committed
81
					var array_type = (ArrayType) f.variable_type;
82

83 84 85 86
					if (!array_type.fixed_length) {
						var len_type = int_type.copy ();

						for (int dim = 1; dim <= array_type.rank; dim++) {
87
							string length_cname;
88 89
							if (get_ccode_array_length_name (f) != null) {
								length_cname = get_ccode_array_length_name (f);
90 91 92
							} else {
								length_cname = get_array_length_cname (f.name, dim);
							}
93
							instance_struct.add_field (get_ccode_name (len_type), length_cname);
94
						}
95

96
						if (array_type.rank == 1 && f.is_internal_symbol ()) {
97
							instance_struct.add_field (get_ccode_name (len_type), get_array_size_cname (f.name));
98
						}
99
					}
Jürg Billeter's avatar
Jürg Billeter committed
100 101
				} else if (f.variable_type is DelegateType) {
					var delegate_type = (DelegateType) f.variable_type;
102 103
					if (delegate_type.delegate_symbol.has_target) {
						// create field to store delegate target
104
						instance_struct.add_field ("gpointer", get_ccode_delegate_target_name (f));
Jürg Billeter's avatar
Jürg Billeter committed
105 106 107
						if (delegate_type.value_owned) {
							instance_struct.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (f.name));
						}
108 109 110
					}
				}
			}
111 112
		}

113
		if (st.base_struct == null) {
114
			decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (get_ccode_name (st)), new CCodeVariableDeclarator (get_ccode_name (st))));
115

116 117
			decl_space.add_type_definition (instance_struct);
		} else {
118
			decl_space.add_type_declaration (new CCodeTypeDefinition (get_ccode_name (st.base_struct), new CCodeVariableDeclarator (get_ccode_name (st))));
119
		}
120

121
		var function = new CCodeFunction (get_ccode_dup_function (st), get_ccode_name (st) + "*");
122 123 124
		if (st.is_private_symbol ()) {
			function.modifiers = CCodeModifiers.STATIC;
		}
125
		function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
126
		decl_space.add_function_declaration (function);
127

128
		function = new CCodeFunction (get_ccode_free_function (st), "void");
129 130 131
		if (st.is_private_symbol ()) {
			function.modifiers = CCodeModifiers.STATIC;
		}
132
		function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
133
		decl_space.add_function_declaration (function);
134 135

		if (st.is_disposable ()) {
136
			function = new CCodeFunction (get_ccode_copy_function (st), "void");
137 138 139
			if (st.is_private_symbol ()) {
				function.modifiers = CCodeModifiers.STATIC;
			}
140 141
			function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
			function.add_parameter (new CCodeParameter ("dest", get_ccode_name (st) + "*"));
142
			decl_space.add_function_declaration (function);
143

144
			function = new CCodeFunction (get_ccode_destroy_function (st), "void");
145 146 147
			if (st.is_private_symbol ()) {
				function.modifiers = CCodeModifiers.STATIC;
			}
148
			function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
149
			decl_space.add_function_declaration (function);
150
		}
151 152 153
	}

	public override void visit_struct (Struct st) {
154
		push_context (new EmitContext (st));
155
		push_line (st.source_reference);
156

157 158
		var old_instance_finalize_context = instance_finalize_context;
		instance_finalize_context = new EmitContext ();
159

160
		generate_struct_declaration (st, cfile);
161 162

		if (!st.is_internal_symbol ()) {
163
			generate_struct_declaration (st, header_file);
164
		}
165
		if (!st.is_private_symbol ()) {
166
			generate_struct_declaration (st, internal_header_file);
167
		}
168

169
		if (!st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type ()) {
170 171 172 173
			if (st.is_disposable ()) {
				begin_struct_destroy_function (st);
			}
		}
174

175
		st.accept_children (this);
176

177
		if (!st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type ()) {
178 179 180 181
			if (st.is_disposable ()) {
				add_struct_copy_function (st);
				add_struct_destroy_function (st);
			}
182

183 184 185
			add_struct_dup_function (st);
			add_struct_free_function (st);
		}
186

187
		instance_finalize_context = old_instance_finalize_context;
188

189
		pop_line ();
190
		pop_context ();
191
	}
192

193
	void add_struct_dup_function (Struct st) {
194
		var function = new CCodeFunction (get_ccode_dup_function (st), get_ccode_name (st) + "*");
195 196 197 198
		if (st.access == SymbolAccessibility.PRIVATE) {
			function.modifiers = CCodeModifiers.STATIC;
		}

199
		function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
200

201
		push_function (function);
202

203
		ccode.add_declaration (get_ccode_name (st) + "*", new CCodeVariableDeclarator ("dup"));
204

Jürg Billeter's avatar
Jürg Billeter committed
205 206 207 208
		var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
		creation_call.add_argument (new CCodeConstant (get_ccode_name (st)));
		creation_call.add_argument (new CCodeConstant ("1"));
		ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
209 210

		if (st.is_disposable ()) {
211
			var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
212 213
			copy_call.add_argument (new CCodeIdentifier ("self"));
			copy_call.add_argument (new CCodeIdentifier ("dup"));
214
			ccode.add_expression (copy_call);
215
		} else {
216
			cfile.add_include ("string.h");
217

218
			var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
219
			sizeof_call.add_argument (new CCodeConstant (get_ccode_name (st)));
220 221 222 223 224

			var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
			copy_call.add_argument (new CCodeIdentifier ("dup"));
			copy_call.add_argument (new CCodeIdentifier ("self"));
			copy_call.add_argument (sizeof_call);
225
			ccode.add_expression (copy_call);
226 227
		}

228
		ccode.add_return (new CCodeIdentifier ("dup"));
229

230
		pop_function ();
231

232
		cfile.add_function (function);
233 234 235
	}

	void add_struct_free_function (Struct st) {
236
		var function = new CCodeFunction (get_ccode_free_function (st), "void");
237 238 239 240
		if (st.access == SymbolAccessibility.PRIVATE) {
			function.modifiers = CCodeModifiers.STATIC;
		}

241
		function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
242

243
		push_function (function);
244 245

		if (st.is_disposable ()) {
246
			var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
247
			destroy_call.add_argument (new CCodeIdentifier ("self"));
248
			ccode.add_expression (destroy_call);
249 250
		}

Jürg Billeter's avatar
Jürg Billeter committed
251 252 253
		var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
		free_call.add_argument (new CCodeIdentifier ("self"));
		ccode.add_expression (free_call);
254

255
		pop_function ();
256

257
		cfile.add_function (function);
258 259
	}

260
	void add_struct_copy_function (Struct st) {
261
		var function = new CCodeFunction (get_ccode_copy_function (st), "void");
262 263 264 265
		if (st.access == SymbolAccessibility.PRIVATE) {
			function.modifiers = CCodeModifiers.STATIC;
		}

266 267
		function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
		function.add_parameter (new CCodeParameter ("dest", get_ccode_name (st) + "*"));
268

269
		push_function (function);
270

271
		var dest_struct = new GLibValue (get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
272 273
		foreach (var f in st.get_fields ()) {
			if (f.binding == MemberBinding.INSTANCE) {
274
				var value = load_field (f, load_this_parameter ((TypeSymbol) st));
Jürg Billeter's avatar
Jürg Billeter committed
275
				if (requires_copy (f.variable_type))  {
276 277
					value = copy_value (value, f);
					if (value == null) {
278 279 280
						// error case, continue to avoid critical
						continue;
					}
281
				}
282
				store_field (f, dest_struct, value);
283 284 285
			}
		}

286
		pop_function ();
287

288
		cfile.add_function (function);
289 290
	}

291 292 293
	void begin_struct_destroy_function (Struct st) {
		push_context (instance_finalize_context);

294
		var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
295 296 297 298
		if (st.access == SymbolAccessibility.PRIVATE) {
			function.modifiers = CCodeModifiers.STATIC;
		}

299
		function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
300

301
		push_function (function);
302

303 304
		pop_context ();
	}
305

306 307
	void add_struct_destroy_function (Struct st) {
		cfile.add_function (instance_finalize_context.ccode);
308
	}
309
}
310