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

 * 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>
 *	Raffaele Sandrini <rasa@gmx.ch>
 */

using GLib;
25
using Gee;
Jürg Billeter's avatar
Jürg Billeter committed
26

27
public class Vala.CCodeGenerator {
28
	private CCodeIncludeDirective get_internal_include (string! filename) {
Jürg Billeter's avatar
Jürg Billeter committed
29 30 31
		return new CCodeIncludeDirective (filename, context.library == null);
	}

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
	private CCodeForStatement get_vala_array_free_loop (bool have_length) {
		var cbody = new CCodeBlock ();
		var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*");
		var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));

		var cfreecall = new CCodeFunctionCall (new CCodeIdentifier ("destroy_func"));
		cfreecall.add_argument (cea);

		CCodeExpression cforcond;

		if (have_length) {
			var cfreecond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
			cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
			cbody.add_statement (new CCodeIfStatement (cfreecond, new CCodeExpressionStatement (cfreecall)));
		} else {
			cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
			cbody.add_statement (new CCodeExpressionStatement (cfreecall));
		}

		var cfor = new CCodeForStatement (cforcond, cbody);
		cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
		cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))));

		return cfor;
	}

58 59 60 61 62 63 64 65 66 67 68 69 70 71
	private void append_vala_array_free () {
		var fun = new CCodeFunction ("_vala_array_free", "void");
		fun.modifiers = CCodeModifiers.STATIC;
		fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
		fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
		fun.add_parameter (new CCodeFormalParameter ("destroy_func", "GDestroyNotify"));
		source_type_member_declaration.append (fun.copy ());

		var cdofree = new CCodeBlock ();

		var citdecl = new CCodeDeclaration ("int");
		citdecl.add_declarator (new CCodeVariableDeclarator ("i"));
		cdofree.add_statement (citdecl);

72 73 74
		var clencheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN_OR_EQUAL, new CCodeIdentifier ("array_length"), new CCodeConstant ("0"));
		var ciflen = new CCodeIfStatement (clencheck, get_vala_array_free_loop (true), get_vala_array_free_loop (false));
		cdofree.add_statement (ciflen);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138

		var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
		var ccondfunc = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("destroy_func"), new CCodeConstant ("NULL"));
		var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccondarr, ccondfunc), cdofree);
		fun.block = new CCodeBlock ();
		fun.block.add_statement (cif);

		var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
		carrfree.add_argument (new CCodeIdentifier ("array"));
		fun.block.add_statement (new CCodeExpressionStatement (carrfree));

		source_type_member_definition.append (fun);
	}

	private void append_vala_array_move () {
		string_h_needed = true;

		// assumes that overwritten array elements are null before invocation
		// FIXME will leak memory if that's not the case
		var fun = new CCodeFunction ("_vala_array_move", "void");
		fun.modifiers = CCodeModifiers.STATIC;
		fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
		fun.add_parameter (new CCodeFormalParameter ("element_size", "gsize"));
		fun.add_parameter (new CCodeFormalParameter ("src", "gint"));
		fun.add_parameter (new CCodeFormalParameter ("dest", "gint"));
		fun.add_parameter (new CCodeFormalParameter ("length", "gint"));
		source_type_member_declaration.append (fun.copy ());

		var array = new CCodeIdentifier ("array");
		var element_size = new CCodeIdentifier ("element_size");
		var length = new CCodeIdentifier ("length");
		var src = new CCodeIdentifier ("src");
		var dest = new CCodeIdentifier ("dest");
		var src_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, src, element_size));
		var dest_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest, element_size));
		var dest_end_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dest, length)), element_size));

		fun.block = new CCodeBlock ();

		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_memmove"));
		ccall.add_argument (dest_address);
		ccall.add_argument (src_address);
		ccall.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
		fun.block.add_statement (new CCodeExpressionStatement (ccall));

		var czero1 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
		czero1.add_argument (src_address);
		czero1.add_argument (new CCodeConstant ("0"));
		czero1.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, dest, src)), element_size));
		var czeroblock1 = new CCodeBlock ();
		czeroblock1.add_statement (new CCodeExpressionStatement (czero1));

		var czero2 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
		czero2.add_argument (dest_end_address);
		czero2.add_argument (new CCodeConstant ("0"));
		czero2.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, src, dest)), element_size));
		var czeroblock2 = new CCodeBlock ();
		czeroblock2.add_statement (new CCodeExpressionStatement (czero2));

		fun.block.add_statement (new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest), czeroblock1, czeroblock2));

		source_type_member_definition.append (fun);
	}

139
	public override void visit_source_file (SourceFile! source_file) {
Jürg Billeter's avatar
Jürg Billeter committed
140 141 142 143 144 145 146 147 148 149 150
		header_begin = new CCodeFragment ();
		header_type_declaration = new CCodeFragment ();
		header_type_definition = new CCodeFragment ();
		header_type_member_declaration = new CCodeFragment ();
		source_begin = new CCodeFragment ();
		source_include_directives = new CCodeFragment ();
		source_type_member_declaration = new CCodeFragment ();
		source_type_member_definition = new CCodeFragment ();
		source_signal_marshaller_definition = new CCodeFragment ();
		source_signal_marshaller_declaration = new CCodeFragment ();
		
151
		user_marshal_set = new HashSet<string> (str_hash, str_equal);
Jürg Billeter's avatar
Jürg Billeter committed
152 153 154 155
		
		next_temp_var_id = 0;
		
		string_h_needed = false;
Jürg Billeter's avatar
Jürg Billeter committed
156 157
		requires_free_checked = false;
		requires_array_free = false;
Jürg Billeter's avatar
Jürg Billeter committed
158
		requires_array_move = false;
Jürg Billeter's avatar
Jürg Billeter committed
159 160 161
		
		header_begin.append (new CCodeIncludeDirective ("glib.h"));
		header_begin.append (new CCodeIncludeDirective ("glib-object.h"));
162 163 164 165 166
		if (context.basedir != null || context.library != null) {
			source_include_directives.append (new CCodeIncludeDirective (source_file.get_cinclude_filename ()));
		} else {
			source_include_directives.append (new CCodeIncludeDirective (source_file.get_cinclude_filename (), true));
		}
Jürg Billeter's avatar
Jürg Billeter committed
167
		
168 169 170
		Gee.List<string> used_includes = new ArrayList<string> (str_equal);
		used_includes.add ("glib.h");
		used_includes.add ("glib-object.h");
171
		used_includes.add (source_file.get_cinclude_filename ());
Jürg Billeter's avatar
Jürg Billeter committed
172
		
173 174 175 176
		foreach (string filename in source_file.get_header_external_includes ()) {
			if (!used_includes.contains (filename)) {
				header_begin.append (new CCodeIncludeDirective (filename));
				used_includes.add (filename);
Jürg Billeter's avatar
Jürg Billeter committed
177 178
			}
		}
179 180 181 182
		foreach (string filename in source_file.get_header_internal_includes ()) {
			if (!used_includes.contains (filename)) {
				header_begin.append (get_internal_include (filename));
				used_includes.add (filename);
Jürg Billeter's avatar
Jürg Billeter committed
183 184
			}
		}
185 186 187 188
		foreach (string filename in source_file.get_source_external_includes ()) {
			if (!used_includes.contains (filename)) {
				source_include_directives.append (new CCodeIncludeDirective (filename));
				used_includes.add (filename);
Jürg Billeter's avatar
Jürg Billeter committed
189 190
			}
		}
191 192 193 194
		foreach (string filename in source_file.get_source_internal_includes ()) {
			if (!used_includes.contains (filename)) {
				source_include_directives.append (get_internal_include (filename));
				used_includes.add (filename);
Jürg Billeter's avatar
Jürg Billeter committed
195 196 197 198
			}
		}
		if (source_file.is_cycle_head) {
			foreach (SourceFile cycle_file in source_file.cycle.files) {
199 200 201
				foreach (CodeNode node in cycle_file.get_nodes ()) {
					if (node is Struct) {
						var st = (Struct) node;
Jürg Billeter's avatar
Jürg Billeter committed
202
						header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ())));
203 204
					} else if (node is Class) {
						var cl = (Class) node;
205 206 207 208
						if (!cl.is_static) {
							header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ())));
							header_type_declaration.append (new CCodeTypeDefinition ("struct _%sClass".printf (cl.get_cname ()), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ()))));
						}
209 210
					} else if (node is Interface) {
						var iface = (Interface) node;
211 212 213 214
						if (!iface.is_static && !iface.declaration_only) {
							header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ())));
							header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_type_cname ()), new CCodeVariableDeclarator (iface.get_type_cname ())));
						}
Jürg Billeter's avatar
Jürg Billeter committed
215 216 217 218
					}
				}
			}
		}
219 220 221

		source_file.accept_children (this);

222
		var header_define = get_define_for_filename (source_file.get_cinclude_filename ());
Jürg Billeter's avatar
Jürg Billeter committed
223
		
Jürg Billeter's avatar
Jürg Billeter committed
224 225 226 227 228
		/* generate hardcoded "well-known" macros */
		if (requires_free_checked) {
			source_begin.append (new CCodeMacroReplacement ("VALA_FREE_CHECKED(o,f)", "((o) == NULL ? NULL : ((o) = (f (o), NULL)))"));
		}
		if (requires_array_free) {
229
			append_vala_array_free ();
Jürg Billeter's avatar
Jürg Billeter committed
230
		}
Jürg Billeter's avatar
Jürg Billeter committed
231
		if (requires_array_move) {
232
			append_vala_array_move ();
Jürg Billeter's avatar
Jürg Billeter committed
233
		}
Jürg Billeter's avatar
Jürg Billeter committed
234
		
Jürg Billeter's avatar
Jürg Billeter committed
235 236 237 238
		if (string_h_needed) {
			source_include_directives.append (new CCodeIncludeDirective ("string.h"));
		}

Jürg Billeter's avatar
Jürg Billeter committed
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
		CCodeComment comment = null;
		if (source_file.comment != null) {
			comment = new CCodeComment (source_file.comment);
		}

		var writer = new CCodeWriter (source_file.get_cheader_filename ());
		if (comment != null) {
			comment.write (writer);
		}
		writer.write_newline ();
		var once = new CCodeOnceSection (header_define);
		once.append (new CCodeNewline ());
		once.append (header_begin);
		once.append (new CCodeNewline ());
		once.append (new CCodeIdentifier ("G_BEGIN_DECLS"));
		once.append (new CCodeNewline ());
		once.append (new CCodeNewline ());
		once.append (header_type_declaration);
		once.append (new CCodeNewline ());
		once.append (header_type_definition);
		once.append (new CCodeNewline ());
		once.append (header_type_member_declaration);
		once.append (new CCodeNewline ());
		once.append (new CCodeIdentifier ("G_END_DECLS"));
		once.append (new CCodeNewline ());
		once.append (new CCodeNewline ());
		once.write (writer);
		writer.close ();
		
		writer = new CCodeWriter (source_file.get_csource_filename ());
269
		writer.line_directives = context.debug;
Jürg Billeter's avatar
Jürg Billeter committed
270 271 272 273 274 275 276
		if (comment != null) {
			comment.write (writer);
		}
		source_begin.write (writer);
		writer.write_newline ();
		source_include_directives.write (writer);
		writer.write_newline ();
277
		source_type_member_declaration.write_declaration (writer);
Jürg Billeter's avatar
Jürg Billeter committed
278 279
		source_type_member_declaration.write (writer);
		writer.write_newline ();
280
		source_signal_marshaller_declaration.write_declaration (writer);
Jürg Billeter's avatar
Jürg Billeter committed
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
		source_signal_marshaller_declaration.write (writer);
		writer.write_newline ();
		source_type_member_definition.write (writer);
		writer.write_newline ();
		source_signal_marshaller_definition.write (writer);
		writer.write_newline ();
		writer.close ();

		header_begin = null;
		header_type_declaration = null;
		header_type_definition = null;
		header_type_member_declaration = null;
		source_begin = null;
		source_include_directives = null;
		source_type_member_declaration = null;
		source_type_member_definition = null;
		source_signal_marshaller_definition = null;
		source_signal_marshaller_declaration = null;
	}
300
	
301
	private static string get_define_for_filename (string! filename) {
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
		var define = new String ("__");
		
		var i = filename;
		while (i.len () > 0) {
			var c = i.get_char ();
			if (c.isalnum  () && c < 0x80) {
				define.append_unichar (c.toupper ());
			} else {
				define.append_c ('_');
			}
		
			i = i.next_char ();
		}
		
		define.append ("__");
		
		return define.str;
	}
Jürg Billeter's avatar
Jürg Billeter committed
320
}