dova: Add assert support
[vala-lang.git] / codegen / valadovavaluemodule.vala
blob1b723fe68969d156ead7db0aaf40d91a09394368
1 /* valadovavaluemodule.vala
3 * Copyright (C) 2009-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 internal class Vala.DovaValueModule : DovaObjectModule {
24 public DovaValueModule (CCodeGenerator codegen, CCodeModule? next) {
25 base (codegen, next);
28 public override void generate_class_declaration (Class cl, CCodeDeclarationSpace decl_space) {
29 if (cl.base_class == null ||
30 cl.base_class.get_full_name () != "Dova.Value") {
31 base.generate_class_declaration (cl, decl_space);
32 return;
35 if (decl_space.add_symbol_declaration (cl, cl.get_cname ())) {
36 return;
39 var type_fun = new CCodeFunction ("%s_type_get".printf (cl.get_lower_case_cname ()), "DovaType *");
40 if (cl.access == SymbolAccessibility.PRIVATE) {
41 type_fun.modifiers = CCodeModifiers.STATIC;
43 decl_space.add_type_member_declaration (type_fun);
45 var type_init_fun = new CCodeFunction ("%s_type_init".printf (cl.get_lower_case_cname ()));
46 type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
47 if (cl.access == SymbolAccessibility.PRIVATE) {
48 type_init_fun.modifiers = CCodeModifiers.STATIC;
50 decl_space.add_type_member_declaration (type_init_fun);
52 var instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ()));
54 foreach (Field f in cl.get_fields ()) {
55 if (f.binding == MemberBinding.INSTANCE) {
56 generate_type_declaration (f.field_type, decl_space);
58 string field_ctype = f.field_type.get_cname ();
59 if (f.is_volatile) {
60 field_ctype = "volatile " + field_ctype;
63 string cname = f.get_cname ();
64 var array_type = f.field_type as ArrayType;
65 if (array_type != null && array_type.inline_allocated) {
66 cname += "[]";
69 instance_struct.add_field (field_ctype, cname);
73 decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ())));
74 decl_space.add_type_definition (instance_struct);
76 if (cl.get_full_name () == "string") {
77 generate_method_declaration ((Method) cl.scope.lookup ("ref"), decl_space);
78 generate_method_declaration ((Method) cl.scope.lookup ("unref"), decl_space);
81 add_value_assert (cl, decl_space);
84 public override void visit_class (Class cl) {
85 if (cl.base_class == null ||
86 cl.base_class.get_full_name () != "Dova.Value") {
87 base.visit_class (cl);
88 return;
91 var old_symbol = current_symbol;
92 current_symbol = cl;
94 generate_class_declaration (cl, source_declarations);
96 if (!cl.is_internal_symbol ()) {
97 generate_class_declaration (cl, header_declarations);
99 generate_class_declaration (cl, internal_header_declarations);
102 var cdecl = new CCodeDeclaration ("DovaType *");
103 cdecl.add_declarator (new CCodeVariableDeclarator ("%s_type".printf (cl.get_lower_case_cname ()), new CCodeConstant ("NULL")));
104 cdecl.modifiers = CCodeModifiers.STATIC;
105 source_declarations.add_type_member_declaration (cdecl);
107 var type_fun = new CCodeFunction ("%s_type_get".printf (cl.get_lower_case_cname ()), "DovaType *");
108 type_fun.block = new CCodeBlock ();
110 var type_init_block = new CCodeBlock ();
112 generate_method_declaration ((Method) object_class.scope.lookup ("alloc"), source_declarations);
113 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("base_type")).set_accessor, source_declarations);
114 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("type_size")).get_accessor, source_declarations);
115 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("type_size")).set_accessor, source_declarations);
116 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("value_size")).set_accessor, source_declarations);
118 generate_class_declaration ((Class) context.root.scope.lookup ("Dova").scope.lookup ("Value"), source_declarations);
120 var base_type = new CCodeFunctionCall (new CCodeIdentifier ("dova_value_type_get"));
122 var base_type_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_type_size"));
123 base_type_size.add_argument (base_type);
125 var calloc_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
126 calloc_call.add_argument (new CCodeConstant ("1"));
127 calloc_call.add_argument (base_type_size);
129 type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())), calloc_call)));
131 generate_class_declaration ((Class) object_class, source_declarations);
133 type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())), "DovaObject *"), "type"), new CCodeFunctionCall (new CCodeIdentifier ("dova_type_type_get")))));
135 var set_base_type = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_base_type"));
136 set_base_type.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
137 set_base_type.add_argument (base_type);
138 type_init_block.add_statement (new CCodeExpressionStatement (set_base_type));
140 var set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_type_size"));
141 set_size.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
142 set_size.add_argument (base_type_size);
143 type_init_block.add_statement (new CCodeExpressionStatement (set_size));
145 var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (cl.get_lower_case_cname ())));
146 type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
147 type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
149 type_fun.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ()))), type_init_block));
151 type_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ()))));
153 source_type_member_definition.append (type_fun);
155 var type_init_fun = new CCodeFunction ("%s_type_init".printf (cl.get_lower_case_cname ()));
156 type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
157 type_init_fun.block = new CCodeBlock ();
159 type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_value_type_init"));
160 type_init_call.add_argument (new CCodeIdentifier ("type"));
161 type_init_fun.block.add_statement (new CCodeExpressionStatement (type_init_call));
163 declare_set_value_copy_function (source_declarations);
165 var value_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_copy"));
166 value_copy_call.add_argument (new CCodeIdentifier ("%s_type".printf (cl.get_lower_case_cname ())));
167 value_copy_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("string_copy"), "void (*)(void *, int32_t, void *, int32_t)"));
168 type_init_fun.block.add_statement (new CCodeExpressionStatement (value_copy_call));
170 var function = new CCodeFunction ("string_copy", "void");
171 function.modifiers = CCodeModifiers.STATIC;
172 function.add_parameter (new CCodeFormalParameter ("dest", "string **"));
173 function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
174 function.add_parameter (new CCodeFormalParameter ("src", "string **"));
175 function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
177 function.block = new CCodeBlock ();
178 var cfrag = new CCodeFragment ();
179 function.block.add_statement (cfrag);
181 var dest = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("dest"), new CCodeIdentifier ("dest_index"));
182 var src = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("src"), new CCodeIdentifier ("src_index"));
184 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("string_unref"));
185 unref_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest));
186 var unref_block = new CCodeBlock ();
187 unref_block.add_statement (new CCodeExpressionStatement (unref_call));
188 unref_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), new CCodeConstant ("NULL"))));
189 function.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), unref_block));
191 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("string_ref"));
192 ref_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, src));
193 var ref_block = new CCodeBlock ();
194 ref_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), ref_call)));
195 function.block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("src"), ref_block));
197 source_type_member_definition.append (function);
199 if (cl.scope.lookup ("equals") is Method) {
200 var value_equals_fun = new CCodeFunction ("%s_value_equals".printf (cl.get_lower_case_cname ()), "bool");
201 value_equals_fun.modifiers = CCodeModifiers.STATIC;
202 value_equals_fun.add_parameter (new CCodeFormalParameter ("value", cl.get_cname () + "**"));
203 value_equals_fun.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
204 value_equals_fun.add_parameter (new CCodeFormalParameter ("other", cl.get_cname () + "**"));
205 value_equals_fun.add_parameter (new CCodeFormalParameter ("other_index", "int32_t"));
206 value_equals_fun.block = new CCodeBlock ();
207 var val = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("value"), new CCodeIdentifier ("value_index"));
208 var other = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("other"), new CCodeIdentifier ("other_index"));
209 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_equals".printf (cl.get_lower_case_cname ())));
210 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, val));
211 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, other));
212 value_equals_fun.block.add_statement (new CCodeReturnStatement (ccall));
213 source_type_member_definition.append (value_equals_fun);
215 declare_set_value_equals_function (source_declarations);
217 var value_equals_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_equals"));
218 value_equals_call.add_argument (new CCodeIdentifier ("type"));
219 value_equals_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_value_equals".printf (cl.get_lower_case_cname ())), "bool (*)(void *, int32_t, void *, int32_t)"));
220 type_init_fun.block.add_statement (new CCodeExpressionStatement (value_equals_call));
223 if (cl.scope.lookup ("hash") is Method) {
224 var value_hash_fun = new CCodeFunction ("%s_value_hash".printf (cl.get_lower_case_cname ()), "int32_t");
225 value_hash_fun.modifiers = CCodeModifiers.STATIC;
226 value_hash_fun.add_parameter (new CCodeFormalParameter ("value", cl.get_cname () + "**"));
227 value_hash_fun.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
228 value_hash_fun.block = new CCodeBlock ();
229 var val = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("value"), new CCodeIdentifier ("value_index"));
230 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_hash".printf (cl.get_lower_case_cname ())));
231 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, val));
232 value_hash_fun.block.add_statement (new CCodeReturnStatement (ccall));
233 source_type_member_definition.append (value_hash_fun);
235 declare_set_value_hash_function (source_declarations);
237 var value_hash_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_hash"));
238 value_hash_call.add_argument (new CCodeIdentifier ("type"));
239 value_hash_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_value_hash".printf (cl.get_lower_case_cname ())), "int32_t (*)(void *, int32_t)"));
240 type_init_fun.block.add_statement (new CCodeExpressionStatement (value_hash_call));
243 source_type_member_definition.append (type_init_fun);
245 cl.accept_children (codegen);
247 current_symbol = old_symbol;
250 public override void visit_creation_method (CreationMethod m) {
251 if (current_type_symbol is Class &&
252 (current_class.base_class == null ||
253 current_class.base_class.get_full_name () != "Dova.Value")) {
254 base.visit_creation_method (m);
255 return;
258 visit_method (m);
261 public override void generate_struct_declaration (Struct st, CCodeDeclarationSpace decl_space) {
262 base.generate_struct_declaration (st, decl_space);
264 if (decl_space.add_symbol_declaration (st, st.get_copy_function ())) {
265 return;
268 decl_space.add_include ("stdint.h");
270 generate_class_declaration (type_class, decl_space);
272 var type_fun = new CCodeFunction ("%s_type_get".printf (st.get_lower_case_cname ()), "DovaType *");
273 if (st.access == SymbolAccessibility.PRIVATE) {
274 type_fun.modifiers = CCodeModifiers.STATIC;
276 decl_space.add_type_member_declaration (type_fun);
278 var type_init_fun = new CCodeFunction ("%s_type_init".printf (st.get_lower_case_cname ()));
279 type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
280 if (st.access == SymbolAccessibility.PRIVATE) {
281 type_init_fun.modifiers = CCodeModifiers.STATIC;
283 decl_space.add_type_member_declaration (type_init_fun);
285 var function = new CCodeFunction (st.get_copy_function (), "void");
286 if (st.access == SymbolAccessibility.PRIVATE) {
287 function.modifiers = CCodeModifiers.STATIC;
290 function.add_parameter (new CCodeFormalParameter ("dest", st.get_cname () + "*"));
291 function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
292 function.add_parameter (new CCodeFormalParameter ("src", st.get_cname () + "*"));
293 function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
295 decl_space.add_type_member_declaration (function);
297 add_value_assert (st, decl_space);
300 void add_value_assert (TypeSymbol sym, CCodeDeclarationSpace decl_space) {
301 string cname = sym.get_cname ();
302 if (sym is Class) {
303 cname += "*";
306 string assert_body;
307 var compare_method = sym.scope.lookup ("compare") as Method;
308 if (compare_method != null) {
309 assert_body = "do { %s __v1 = (v1); %s __v2 = (v2); if (%s (__v1, __v2) cmp 0); else dova_assert_compare (string_create_from_cstring (#v1 \" \" #cmp \" \" #v2), %s_to_string (v1), string_create_from_cstring (#cmp), %s_to_string (v2)); } while (0)".printf (cname, cname, compare_method.get_cname (), sym.get_lower_case_cname (), sym.get_lower_case_cname ());
310 } else {
311 assert_body = "do { %s __v1 = (v1); %s __v2 = (v2); if (__v1 cmp __v2); else dova_assert_compare (string_create_from_cstring (#v1 \" \" #cmp \" \" #v2), %s_to_string (v1), string_create_from_cstring (#cmp), %s_to_string (v2)); } while (0)".printf (cname, cname, sym.get_lower_case_cname (), sym.get_lower_case_cname ());
313 var assert_macro = new CCodeMacroReplacement ("%s_assert(v1, cmp, v2)".printf (sym.get_lower_case_cname ()), assert_body);
314 decl_space.add_type_member_declaration (assert_macro);
317 public override void visit_struct (Struct st) {
318 base.visit_struct (st);
320 source_declarations.add_include ("stddef.h");
321 // calloc
322 source_declarations.add_include ("stdlib.h");
324 var cdecl = new CCodeDeclaration ("DovaType *");
325 cdecl.add_declarator (new CCodeVariableDeclarator ("%s_type".printf (st.get_lower_case_cname ()), new CCodeConstant ("NULL")));
326 cdecl.modifiers = CCodeModifiers.STATIC;
327 source_declarations.add_type_member_declaration (cdecl);
329 var type_fun = new CCodeFunction ("%s_type_get".printf (st.get_lower_case_cname ()), "DovaType *");
330 type_fun.block = new CCodeBlock ();
332 var type_init_block = new CCodeBlock ();
334 generate_method_declaration ((Method) object_class.scope.lookup ("alloc"), source_declarations);
335 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("base_type")).get_accessor, source_declarations);
336 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("base_type")).set_accessor, source_declarations);
337 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("object_size")).get_accessor, source_declarations);
338 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("object_size")).set_accessor, source_declarations);
339 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("type_size")).get_accessor, source_declarations);
340 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("type_size")).set_accessor, source_declarations);
341 generate_property_accessor_declaration (((Property) type_class.scope.lookup ("value_size")).set_accessor, source_declarations);
343 generate_class_declaration ((Class) context.root.scope.lookup ("Dova").scope.lookup ("Value"), source_declarations);
345 var base_type = new CCodeFunctionCall (new CCodeIdentifier ("dova_value_type_get"));
347 var base_type_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_type_size"));
348 base_type_size.add_argument (base_type);
350 var calloc_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
351 calloc_call.add_argument (new CCodeConstant ("1"));
352 calloc_call.add_argument (base_type_size);
354 type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())), calloc_call)));
356 generate_class_declaration ((Class) object_class, source_declarations);
358 type_init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())), "DovaObject *"), "type"), new CCodeFunctionCall (new CCodeIdentifier ("dova_type_type_get")))));
360 var set_base_type = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_base_type"));
361 set_base_type.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
362 set_base_type.add_argument (base_type);
363 type_init_block.add_statement (new CCodeExpressionStatement (set_base_type));
365 var base_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_get_object_size"));
366 base_size.add_argument (base_type);
368 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
369 sizeof_call.add_argument (new CCodeIdentifier (st.get_cname ()));
370 var set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_object_size"));
371 set_size.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
372 set_size.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, base_size, sizeof_call));
373 type_init_block.add_statement (new CCodeExpressionStatement (set_size));
375 set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_size"));
376 set_size.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
377 set_size.add_argument (sizeof_call);
378 type_init_block.add_statement (new CCodeExpressionStatement (set_size));
380 set_size = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_type_size"));
381 set_size.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
382 set_size.add_argument (base_type_size);
383 type_init_block.add_statement (new CCodeExpressionStatement (set_size));
385 var type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_type_init".printf (st.get_lower_case_cname ())));
386 type_init_call.add_argument (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ())));
387 type_init_block.add_statement (new CCodeExpressionStatement (type_init_call));
389 type_fun.block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ()))), type_init_block));
391 type_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("%s_type".printf (st.get_lower_case_cname ()))));
393 source_type_member_definition.append (type_fun);
395 var type_init_fun = new CCodeFunction ("%s_type_init".printf (st.get_lower_case_cname ()));
396 type_init_fun.add_parameter (new CCodeFormalParameter ("type", "DovaType *"));
397 type_init_fun.block = new CCodeBlock ();
399 type_init_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_value_type_init"));
400 type_init_call.add_argument (new CCodeIdentifier ("type"));
401 type_init_fun.block.add_statement (new CCodeExpressionStatement (type_init_call));
403 declare_set_value_copy_function (source_declarations);
405 var value_copy_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_copy"));
406 value_copy_call.add_argument (new CCodeIdentifier ("type"));
407 value_copy_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_copy".printf (st.get_lower_case_cname ())), "void (*)(void *, int32_t, void *, int32_t)"));
408 type_init_fun.block.add_statement (new CCodeExpressionStatement (value_copy_call));
410 if (st.scope.lookup ("equals") is Method) {
411 var value_equals_fun = new CCodeFunction ("%s_value_equals".printf (st.get_lower_case_cname ()), "bool");
412 value_equals_fun.modifiers = CCodeModifiers.STATIC;
413 value_equals_fun.add_parameter (new CCodeFormalParameter ("value", st.get_cname () + "*"));
414 value_equals_fun.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
415 value_equals_fun.add_parameter (new CCodeFormalParameter ("other", st.get_cname () + "*"));
416 value_equals_fun.add_parameter (new CCodeFormalParameter ("other_index", "int32_t"));
417 value_equals_fun.block = new CCodeBlock ();
418 var val = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("value"), new CCodeIdentifier ("value_index"));
419 var other = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("other"), new CCodeIdentifier ("other_index"));
420 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_equals".printf (st.get_lower_case_cname ())));
421 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, val));
422 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, other));
423 value_equals_fun.block.add_statement (new CCodeReturnStatement (ccall));
424 source_type_member_definition.append (value_equals_fun);
426 declare_set_value_equals_function (source_declarations);
428 var value_equals_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_equals"));
429 value_equals_call.add_argument (new CCodeIdentifier ("type"));
430 value_equals_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_value_equals".printf (st.get_lower_case_cname ())), "bool (*)(void *, int32_t, void *, int32_t)"));
431 type_init_fun.block.add_statement (new CCodeExpressionStatement (value_equals_call));
434 if (st.scope.lookup ("hash") is Method) {
435 var value_hash_fun = new CCodeFunction ("%s_value_hash".printf (st.get_lower_case_cname ()), "int32_t");
436 value_hash_fun.modifiers = CCodeModifiers.STATIC;
437 value_hash_fun.add_parameter (new CCodeFormalParameter ("value", st.get_cname () + "*"));
438 value_hash_fun.add_parameter (new CCodeFormalParameter ("value_index", "int32_t"));
439 value_hash_fun.block = new CCodeBlock ();
440 var val = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("value"), new CCodeIdentifier ("value_index"));
441 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_hash".printf (st.get_lower_case_cname ())));
442 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, val));
443 value_hash_fun.block.add_statement (new CCodeReturnStatement (ccall));
444 source_type_member_definition.append (value_hash_fun);
446 declare_set_value_hash_function (source_declarations);
448 var value_hash_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_set_value_hash"));
449 value_hash_call.add_argument (new CCodeIdentifier ("type"));
450 value_hash_call.add_argument (new CCodeCastExpression (new CCodeIdentifier ("%s_value_hash".printf (st.get_lower_case_cname ())), "int32_t (*)(void *, int32_t)"));
451 type_init_fun.block.add_statement (new CCodeExpressionStatement (value_hash_call));
454 source_type_member_definition.append (type_init_fun);
456 add_struct_copy_function (st);
459 void add_struct_copy_function (Struct st) {
460 var function = new CCodeFunction (st.get_copy_function (), "void");
461 if (st.access == SymbolAccessibility.PRIVATE) {
462 function.modifiers = CCodeModifiers.STATIC;
465 function.add_parameter (new CCodeFormalParameter ("dest", st.get_cname () + "*"));
466 function.add_parameter (new CCodeFormalParameter ("dest_index", "int32_t"));
467 function.add_parameter (new CCodeFormalParameter ("src", st.get_cname () + "*"));
468 function.add_parameter (new CCodeFormalParameter ("src_index", "int32_t"));
470 var cblock = new CCodeBlock ();
471 var cfrag = new CCodeFragment ();
472 cblock.add_statement (cfrag);
474 var dest = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("dest"), new CCodeIdentifier ("dest_index"));
475 var src = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("src"), new CCodeIdentifier ("src_index"));
477 foreach (var f in st.get_fields ()) {
478 if (f.binding == MemberBinding.INSTANCE) {
479 var field = new CCodeMemberAccess.pointer (dest, f.name);
481 var array_type = f.field_type as ArrayType;
482 if (array_type != null && array_type.fixed_length) {
483 for (int i = 0; i < array_type.length; i++) {
484 var element = new CCodeElementAccess (field, new CCodeConstant (i.to_string ()));
486 if (requires_destroy (array_type.element_type)) {
487 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (element, array_type.element_type)));
490 continue;
493 if (requires_destroy (f.field_type)) {
494 var this_access = new MemberAccess.simple ("this");
495 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
496 this_access.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest);
497 var ma = new MemberAccess (this_access, f.name);
498 ma.symbol_reference = f;
499 ma.value_type = f.field_type.copy ();
500 cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (field, f.field_type, ma)));
505 var copy_block = new CCodeBlock ();
507 if (st.get_fields ().size == 0) {
508 copy_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, dest), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, src))));
509 } else {
510 foreach (var f in st.get_fields ()) {
511 if (f.binding == MemberBinding.INSTANCE) {
512 CCodeExpression copy = new CCodeMemberAccess.pointer (src, f.name);
513 var dest_field = new CCodeMemberAccess.pointer (dest, f.name);
515 var array_type = f.field_type as ArrayType;
516 if (array_type != null && array_type.fixed_length) {
517 for (int i = 0; i < array_type.length; i++) {
518 CCodeExpression copy_element = new CCodeElementAccess (copy, new CCodeConstant (i.to_string ()));
519 var dest_field_element = new CCodeElementAccess (dest_field, new CCodeConstant (i.to_string ()));
521 if (requires_copy (array_type.element_type)) {
522 copy_element = get_ref_cexpression (array_type.element_type, copy_element, null, f);
525 copy_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest_field_element, copy_element)));
527 continue;
530 if (requires_copy (f.field_type)) {
531 var this_access = new MemberAccess.simple ("this");
532 this_access.value_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
533 this_access.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, src);
534 var ma = new MemberAccess (this_access, f.name);
535 ma.symbol_reference = f;
536 copy = get_ref_cexpression (f.field_type, copy, ma, f);
539 copy_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (dest_field, copy)));
544 cblock.add_statement (new CCodeIfStatement (new CCodeIdentifier ("src"), copy_block));
546 append_temp_decl (cfrag, temp_vars);
547 temp_vars.clear ();
549 function.block = cblock;
551 source_type_member_definition.append (function);
554 public override void visit_assignment (Assignment assignment) {
555 var generic_type = assignment.left.value_type as GenericType;
556 if (generic_type == null) {
557 base.visit_assignment (assignment);
558 return;
561 var dest = assignment.left;
562 CCodeExpression cdest;
563 CCodeExpression dest_index = new CCodeConstant ("0");
564 var src = assignment.right;
565 CCodeExpression csrc;
566 CCodeExpression src_index = new CCodeConstant ("0");
568 if (src is NullLiteral) {
569 // TODO destroy dest
570 assignment.ccodenode = new CCodeConstant ("0");
571 return;
574 var dest_ea = dest as ElementAccess;
575 var src_ea = src as ElementAccess;
577 if (dest_ea != null) {
578 dest = dest_ea.container;
580 var array_type = dest.value_type as ArrayType;
581 if (array_type != null && !array_type.inline_allocated) {
582 generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
584 var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
585 data_call.add_argument ((CCodeExpression) get_ccodenode (dest));
586 cdest = data_call;
587 } else {
588 cdest = (CCodeExpression) get_ccodenode (dest);
590 dest_index = (CCodeExpression) get_ccodenode (dest_ea.get_indices ().get (0));
591 } else {
592 cdest = (CCodeExpression) get_ccodenode (dest);
595 if (src_ea != null) {
596 src = src_ea.container;
598 var array_type = src.value_type as ArrayType;
599 if (array_type != null && !array_type.inline_allocated) {
600 generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
602 var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
603 data_call.add_argument ((CCodeExpression) get_ccodenode (src));
604 csrc = data_call;
605 } else {
606 csrc = (CCodeExpression) get_ccodenode (src);
608 src_index = (CCodeExpression) get_ccodenode (src_ea.get_indices ().get (0));
609 } else {
610 csrc = (CCodeExpression) get_ccodenode (src);
613 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_value_copy"));
614 if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
615 // generic type
616 ccall.add_argument (new CCodeMemberAccess.pointer (get_type_private_from_type ((ObjectTypeSymbol) generic_type.type_parameter.parent_symbol, new CCodeMemberAccess.pointer (new CCodeIdentifier ("this"), "type")), "%s_type".printf (generic_type.type_parameter.name.down ())));
617 } else {
618 // generic method
619 ccall.add_argument (new CCodeIdentifier ("%s_type".printf (generic_type.type_parameter.name.down ())));
621 ccall.add_argument (cdest);
622 ccall.add_argument (dest_index);
623 ccall.add_argument (csrc);
624 ccall.add_argument (src_index);
625 assignment.ccodenode = ccall;
628 public override void visit_binary_expression (BinaryExpression expr) {
629 var generic_type = expr.left.value_type as GenericType;
630 if (generic_type == null) {
631 base.visit_binary_expression (expr);
632 return;
635 CCodeExpression cleft;
636 CCodeExpression left_index = new CCodeConstant ("0");
637 CCodeExpression cright;
638 CCodeExpression right_index = new CCodeConstant ("0");
640 var left_ea = expr.left as ElementAccess;
641 var right_ea = expr.right as ElementAccess;
643 if (left_ea != null) {
644 generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
646 var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
647 data_call.add_argument ((CCodeExpression) get_ccodenode (left_ea.container));
648 cleft = data_call;
649 left_index = (CCodeExpression) get_ccodenode (left_ea.get_indices ().get (0));
650 } else {
651 cleft = (CCodeExpression) get_ccodenode (expr.left);
654 if (right_ea != null) {
655 generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
657 var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
658 data_call.add_argument ((CCodeExpression) get_ccodenode (right_ea.container));
659 cright = data_call;
660 right_index = (CCodeExpression) get_ccodenode (right_ea.get_indices ().get (0));
661 } else {
662 cright = (CCodeExpression) get_ccodenode (expr.right);
665 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_value_equals"));
666 ccall.add_argument (get_type_id_expression (generic_type));
667 ccall.add_argument (cleft);
668 ccall.add_argument (left_index);
669 ccall.add_argument (cright);
670 ccall.add_argument (right_index);
672 if (expr.operator == BinaryOperator.EQUALITY) {
673 expr.ccodenode = ccall;
674 } else {
675 expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall);
679 bool is_comparison (Expression expr) {
680 var binary_expression = expr as BinaryExpression;
681 if (binary_expression != null) {
682 switch (binary_expression.operator) {
683 case BinaryOperator.LESS_THAN:
684 case BinaryOperator.GREATER_THAN:
685 case BinaryOperator.LESS_THAN_OR_EQUAL:
686 case BinaryOperator.GREATER_THAN_OR_EQUAL:
687 case BinaryOperator.EQUALITY:
688 case BinaryOperator.INEQUALITY:
689 return true;
690 default:
691 return false;
694 return false;
697 bool handle_assert (MethodCall expr) {
698 var args = expr.get_argument_list ();
699 var mtype = expr.call.value_type as MethodType;
700 if (mtype == null || mtype.method_symbol.get_cname () != "dova_assert" ||
701 !(args.get (1) is NullLiteral) ||
702 !is_comparison (args.get (0))) {
703 return false;
706 expr.accept_children (codegen);
708 var binary_expression = (BinaryExpression) args.get (0);
709 var op1 = binary_expression.left;
710 var op2 = binary_expression.right;
712 var type = op1.value_type.data_type;
714 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_assert".printf (type.get_lower_case_cname ())));
715 ccall.add_argument ((CCodeExpression) get_ccodenode (op1));
716 ccall.add_argument (new CCodeConstant (binary_expression.get_operator_string ()));
717 ccall.add_argument ((CCodeExpression) get_ccodenode (op2));
718 expr.ccodenode = ccall;
720 return true;
723 public override void visit_method_call (MethodCall expr) {
724 if (handle_assert (expr)) {
725 return;
728 var ma = expr.call as MemberAccess;
729 if (ma == null || ma.inner == null || !(ma.inner.value_type is GenericType)) {
730 base.visit_method_call (expr);
731 return;
734 // handle method calls on generic types
736 expr.accept_children (codegen);
738 if (ma.member_name == "hash") {
739 var val = ma.inner;
740 CCodeExpression cval;
741 CCodeExpression val_index = new CCodeConstant ("0");
743 var val_ea = val as ElementAccess;
744 if (val_ea != null) {
745 val = val_ea.container;
747 generate_property_accessor_declaration (((Property) array_class.scope.lookup ("data")).get_accessor, source_declarations);
749 var data_call = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_data"));
750 data_call.add_argument ((CCodeExpression) get_ccodenode (val));
751 cval = data_call;
752 val_index = (CCodeExpression) get_ccodenode (val_ea.get_indices ().get (0));
753 } else {
754 cval = (CCodeExpression) get_ccodenode (val);
757 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_type_value_hash"));
758 ccall.add_argument (get_type_id_expression (ma.inner.value_type));
759 ccall.add_argument (cval);
760 ccall.add_argument (val_index);
762 expr.ccodenode = ccall;
766 public override void visit_list_literal (ListLiteral expr) {
767 expr.accept_children (codegen);
769 var array_type = new ArrayType (expr.element_type, 1, expr.source_reference);
770 array_type.inline_allocated = true;
771 array_type.fixed_length = true;
772 array_type.length = expr.get_expressions ().size;
774 var ce = new CCodeCommaExpression ();
775 var temp_var = get_temp_variable (array_type, true, expr);
776 var name_cnode = get_variable_cexpression (temp_var.name);
778 temp_vars.insert (0, temp_var);
780 int i = 0;
781 foreach (Expression e in expr.get_expressions ()) {
782 ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
783 i++;
786 ce.append_expression (name_cnode);
788 var list_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_list_new"));
789 list_creation.add_argument (get_type_id_expression (expr.element_type));
790 list_creation.add_argument (new CCodeConstant (array_type.length.to_string ()));
791 list_creation.add_argument (ce);
793 expr.ccodenode = list_creation;
796 public override void visit_set_literal (SetLiteral expr) {
797 expr.accept_children (codegen);
799 var array_type = new ArrayType (expr.element_type, 1, expr.source_reference);
800 array_type.inline_allocated = true;
801 array_type.fixed_length = true;
802 array_type.length = expr.get_expressions ().size;
804 var ce = new CCodeCommaExpression ();
805 var temp_var = get_temp_variable (array_type, true, expr);
806 var name_cnode = get_variable_cexpression (temp_var.name);
808 temp_vars.insert (0, temp_var);
810 int i = 0;
811 foreach (Expression e in expr.get_expressions ()) {
812 ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
813 i++;
816 ce.append_expression (name_cnode);
818 var set_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_set_new"));
819 set_creation.add_argument (get_type_id_expression (expr.element_type));
820 set_creation.add_argument (new CCodeConstant (array_type.length.to_string ()));
821 set_creation.add_argument (ce);
823 expr.ccodenode = set_creation;
826 public override void visit_map_literal (MapLiteral expr) {
827 expr.accept_children (codegen);
829 var key_array_type = new ArrayType (expr.map_key_type, 1, expr.source_reference);
830 key_array_type.inline_allocated = true;
831 key_array_type.fixed_length = true;
832 key_array_type.length = expr.get_keys ().size;
834 var key_ce = new CCodeCommaExpression ();
835 var key_temp_var = get_temp_variable (key_array_type, true, expr);
836 var key_name_cnode = get_variable_cexpression (key_temp_var.name);
838 temp_vars.insert (0, key_temp_var);
840 var value_array_type = new ArrayType (expr.map_value_type, 1, expr.source_reference);
841 value_array_type.inline_allocated = true;
842 value_array_type.fixed_length = true;
843 value_array_type.length = expr.get_values ().size;
845 var value_ce = new CCodeCommaExpression ();
846 var value_temp_var = get_temp_variable (value_array_type, true, expr);
847 var value_name_cnode = get_variable_cexpression (value_temp_var.name);
849 temp_vars.insert (0, value_temp_var);
851 for (int i = 0; i < expr.get_keys ().size; i++) {
852 key_ce.append_expression (new CCodeAssignment (new CCodeElementAccess (key_name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) expr.get_keys ().get (i).ccodenode));
853 value_ce.append_expression (new CCodeAssignment (new CCodeElementAccess (value_name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) expr.get_values ().get (i).ccodenode));
856 key_ce.append_expression (key_name_cnode);
857 value_ce.append_expression (value_name_cnode);
859 var map_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_map_new"));
860 map_creation.add_argument (get_type_id_expression (expr.map_key_type));
861 map_creation.add_argument (get_type_id_expression (expr.map_value_type));
862 map_creation.add_argument (new CCodeConstant (key_array_type.length.to_string ()));
863 map_creation.add_argument (key_ce);
864 map_creation.add_argument (value_ce);
866 expr.ccodenode = map_creation;
869 public override void visit_tuple (Tuple tuple) {
870 tuple.accept_children (codegen);
872 var type_array_type = new ArrayType (new PointerType (new VoidType ()), 1, tuple.source_reference);
873 type_array_type.inline_allocated = true;
874 type_array_type.fixed_length = true;
875 type_array_type.length = tuple.get_expressions ().size;
877 var type_temp_var = get_temp_variable (type_array_type, true, tuple);
878 var type_name_cnode = get_variable_cexpression (type_temp_var.name);
879 temp_vars.insert (0, type_temp_var);
881 var array_type = new ArrayType (new PointerType (new VoidType ()), 1, tuple.source_reference);
882 array_type.inline_allocated = true;
883 array_type.fixed_length = true;
884 array_type.length = tuple.get_expressions ().size;
886 var temp_var = get_temp_variable (array_type, true, tuple);
887 var name_cnode = get_variable_cexpression (temp_var.name);
888 temp_vars.insert (0, temp_var);
890 var type_ce = new CCodeCommaExpression ();
891 var ce = new CCodeCommaExpression ();
893 int i = 0;
894 foreach (Expression e in tuple.get_expressions ()) {
895 var element_type = tuple.value_type.get_type_arguments ().get (i);
897 type_ce.append_expression (new CCodeAssignment (new CCodeElementAccess (type_name_cnode, new CCodeConstant (i.to_string ())), get_type_id_expression (element_type)));
899 var cexpr = (CCodeExpression) e.ccodenode;
901 var unary = cexpr as CCodeUnaryExpression;
902 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
903 // *expr => expr
904 cexpr = unary.inner;
905 } else if (cexpr is CCodeIdentifier || cexpr is CCodeMemberAccess) {
906 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
907 } else {
908 // if cexpr is e.g. a function call, we can't take the address of the expression
909 // tmp = expr, &tmp
911 var element_temp_var = get_temp_variable (element_type);
912 temp_vars.insert (0, element_temp_var);
913 ce.append_expression (new CCodeAssignment (get_variable_cexpression (element_temp_var.name), cexpr));
914 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (element_temp_var.name));
917 ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), cexpr));
919 i++;
922 type_ce.append_expression (type_name_cnode);
923 ce.append_expression (name_cnode);
925 var tuple_creation = new CCodeFunctionCall (new CCodeIdentifier ("dova_tuple_new"));
926 tuple_creation.add_argument (new CCodeConstant (tuple.get_expressions ().size.to_string ()));
927 tuple_creation.add_argument (type_ce);
928 tuple_creation.add_argument (ce);
930 tuple.ccodenode = tuple_creation;