change run to use meson/ninja and then exec. - remove libvala code from application...
[roobuilder] / src / ccode / valaccodefunction.vala
1 /* valaccodefunction.vala
2  *
3  * Copyright (C) 2006-2012  Jürg Billeter
4  *
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.
9
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.
14
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
18  *
19  * Author:
20  *      Jürg Billeter <j@bitron.ch>
21  */
22
23 using GLib;
24
25 /**
26  * Represents a function declaration in the C code.
27  */
28 public class Vala.CCodeFunction : CCodeNode {
29         /**
30          * The name of this function.
31          */
32         public string name { get; set; }
33
34         /**
35          * The function return type.
36          */
37         public string return_type { get; set; }
38
39         public bool is_declaration { get; set; }
40
41         /**
42          * The function body.
43          */
44         public CCodeBlock block { get; set; }
45
46         /**
47          * The current line directive.
48          */
49         public CCodeLineDirective current_line { get; set; }
50
51         /**
52          * The current block to be written into.
53          */
54         public CCodeBlock current_block { get; set; }
55
56         private List<CCodeParameter> parameters = new ArrayList<CCodeParameter> ();
57
58         List<CCodeStatement> statement_stack = new ArrayList<CCodeStatement> ();
59
60         public CCodeFunction (string name, string return_type = "void") {
61                 this.name = name;
62                 this.return_type = return_type;
63                 this.block = new CCodeBlock ();
64                 current_block = block;
65         }
66
67         /**
68          * Appends the specified parameter to the list of function parameters.
69          *
70          * @param param a formal parameter
71          */
72         public void add_parameter (CCodeParameter param) {
73                 parameters.add (param);
74         }
75
76         public void insert_parameter (int position, CCodeParameter param) {
77                 parameters.insert (position, param);
78         }
79
80         public int get_parameter_count () {
81                 return parameters.size;
82         }
83
84         public CCodeParameter get_parameter (int position) {
85                 return parameters[position];
86         }
87
88         /**
89          * Returns a copy of this function.
90          *
91          * @return copied function
92          */
93         public CCodeFunction copy () {
94                 var func = new CCodeFunction (name, return_type);
95                 func.modifiers = modifiers;
96
97                 /* no deep copy for lists available yet
98                  * func.parameters = parameters.copy ();
99                  */
100                 foreach (CCodeParameter param in parameters) {
101                         func.parameters.add (param);
102                 }
103
104                 func.is_declaration = is_declaration;
105                 func.block = block;
106                 return func;
107         }
108
109         public override void write (CCodeWriter writer) {
110                 writer.write_indent (line);
111                 if (CCodeModifiers.INTERNAL in modifiers) {
112                         writer.write_string (GNUC_INTERNAL);
113                 } else if (is_declaration && CCodeModifiers.EXTERN in modifiers) {
114                         writer.write_string ("VALA_EXTERN ");
115                 }
116                 if (!is_declaration && CCodeModifiers.NO_INLINE in modifiers) {
117                         writer.write_string (GNUC_NO_INLINE);
118                 }
119                 if (CCodeModifiers.STATIC in modifiers) {
120                         writer.write_string ("static ");
121                 }
122                 if (CCodeModifiers.INLINE in modifiers) {
123                         writer.write_string ("inline ");
124                 }
125                 writer.write_string (return_type);
126                 if (is_declaration) {
127                         writer.write_string (" ");
128                 } else {
129                         writer.write_newline ();
130                 }
131                 writer.write_string (name);
132                 writer.write_string (" (");
133                 int param_pos_begin = (is_declaration ? return_type.char_count () + 1 : 0 ) + name.char_count () + 2;
134
135                 bool has_args = (CCodeModifiers.PRINTF in modifiers || CCodeModifiers.SCANF in modifiers);
136                 int i = 0;
137                 int format_arg_index = -1;
138                 int args_index = -1;
139                 foreach (CCodeParameter param in parameters) {
140                         if (i > 0) {
141                                 writer.write_string (",");
142                                 writer.write_newline ();
143                                 writer.write_nspaces (param_pos_begin);
144                         }
145                         param.write (writer);
146                         if (CCodeModifiers.FORMAT_ARG in param.modifiers) {
147                                 format_arg_index = i;
148                         }
149                         if (has_args && param.ellipsis) {
150                                 args_index = i;
151                         } else if (has_args && param.type_name == "va_list" && format_arg_index < 0) {
152                                 format_arg_index = i - 1;
153                         }
154                         i++;
155                 }
156                 if (i == 0) {
157                         writer.write_string ("void");
158                 }
159
160                 writer.write_string (")");
161
162                 if (is_declaration) {
163                         if (CCodeModifiers.DEPRECATED in modifiers) {
164                                 writer.write_string (GNUC_DEPRECATED);
165                         }
166
167                         if (CCodeModifiers.PRINTF in modifiers) {
168                                 format_arg_index = (format_arg_index >= 0 ? format_arg_index + 1 : args_index);
169                                 writer.write_string (GNUC_PRINTF.printf (format_arg_index, args_index + 1));
170                         } else if (CCodeModifiers.SCANF in modifiers) {
171                                 format_arg_index = (format_arg_index >= 0 ? format_arg_index + 1 : args_index);
172                                 writer.write_string (GNUC_SCANF.printf (format_arg_index, args_index + 1));
173                         } else if (format_arg_index >= 0) {
174                                 writer.write_string (GNUC_FORMAT.printf (format_arg_index + 1));
175                         }
176
177                         if (CCodeModifiers.CONST in modifiers) {
178                                 writer.write_string (GNUC_CONST);
179                         }
180                         if (CCodeModifiers.UNUSED in modifiers) {
181                                 writer.write_string (GNUC_UNUSED);
182                         }
183
184                         if (CCodeModifiers.CONSTRUCTOR in modifiers) {
185                                 writer.write_string (" __attribute__((constructor))");
186                         } else if (CCodeModifiers.DESTRUCTOR in modifiers) {
187                                 writer.write_string (" __attribute__((destructor))");
188                         }
189
190                         writer.write_string (";");
191                 } else {
192                         writer.write_newline ();
193                         block.write (writer);
194                         writer.write_newline ();
195                 }
196                 writer.write_newline ();
197         }
198
199         public void add_statement (CCodeNode stmt) {
200                 stmt.line = current_line;
201                 current_block.add_statement (stmt);
202         }
203
204         public void open_block () {
205                 statement_stack.add (current_block);
206                 var parent_block = current_block;
207
208                 current_block = new CCodeBlock ();
209
210                 parent_block.add_statement (current_block);
211         }
212
213         public void open_if (CCodeExpression condition) {
214                 statement_stack.add (current_block);
215                 var parent_block = current_block;
216
217                 current_block = new CCodeBlock ();
218
219                 var cif = new CCodeIfStatement (condition, current_block);
220                 cif.line = current_line;
221                 statement_stack.add (cif);
222
223                 parent_block.add_statement (cif);
224         }
225
226         public void add_else () {
227                 current_block = new CCodeBlock ();
228
229                 var cif = (CCodeIfStatement) statement_stack[statement_stack.size - 1];
230                 cif.line = current_line;
231                 assert (cif.false_statement == null);
232                 cif.false_statement = current_block;
233         }
234
235         public void else_if (CCodeExpression condition) {
236                 var parent_if = (CCodeIfStatement) statement_stack.remove_at (statement_stack.size - 1);
237                 assert (parent_if.false_statement == null);
238
239                 current_block = new CCodeBlock ();
240
241                 var cif = new CCodeIfStatement (condition, current_block);
242                 cif.line = current_line;
243                 parent_if.false_statement = cif;
244                 statement_stack.add (cif);
245         }
246
247         public void open_while (CCodeExpression condition) {
248                 statement_stack.add (current_block);
249                 var parent_block = current_block;
250
251                 current_block = new CCodeBlock ();
252
253                 var cwhile = new CCodeWhileStatement (condition, current_block);
254                 cwhile.line = current_line;
255                 parent_block.add_statement (cwhile);
256         }
257
258         public void open_for (CCodeExpression? initializer, CCodeExpression condition, CCodeExpression? iterator) {
259                 statement_stack.add (current_block);
260                 var parent_block = current_block;
261
262                 current_block = new CCodeBlock ();
263
264                 var cfor = new CCodeForStatement (condition, current_block);
265                 cfor.line = current_line;
266                 if (initializer != null) {
267                         cfor.add_initializer (initializer);
268                 }
269                 if (iterator != null) {
270                         cfor.add_iterator (iterator);
271                 }
272
273                 parent_block.add_statement (cfor);
274         }
275
276         public void open_switch (CCodeExpression expression) {
277                 statement_stack.add (current_block);
278                 var parent_block = current_block;
279
280                 var cswitch = new CCodeSwitchStatement (expression);
281                 cswitch.line = current_line;
282                 current_block = cswitch;
283
284                 parent_block.add_statement (cswitch);
285         }
286
287         public void add_label (string label) {
288                 add_statement (new CCodeLabel (label));
289         }
290
291         public void add_case (CCodeExpression expression) {
292                 add_statement (new CCodeCaseStatement (expression));
293         }
294
295         public void add_default () {
296                 add_statement (new CCodeLabel ("default"));
297         }
298
299         public void add_goto (string target) {
300                 add_statement (new CCodeGotoStatement (target));
301         }
302
303         public void add_expression (CCodeExpression expression) {
304                 add_statement (new CCodeExpressionStatement (expression));
305         }
306
307         public void add_assignment (CCodeExpression left, CCodeExpression right) {
308                 add_expression (new CCodeAssignment (left, right));
309         }
310
311         public void add_return (CCodeExpression? expression = null) {
312                 add_statement (new CCodeReturnStatement (expression));
313         }
314
315         public void add_break () {
316                 add_statement (new CCodeBreakStatement ());
317         }
318
319         public void add_continue () {
320                 add_statement (new CCodeContinueStatement ());
321         }
322
323         public void add_declaration (string type_name, CCodeDeclarator declarator, CCodeModifiers modifiers = 0) {
324                 var stmt = new CCodeDeclaration (type_name);
325                 stmt.add_declarator (declarator);
326                 stmt.modifiers = modifiers;
327                 add_statement (stmt);
328         }
329
330         public void close () {
331                 do {
332                         var top = statement_stack.remove_at (statement_stack.size - 1);
333                         current_block = top as CCodeBlock;
334                 } while (current_block == null);
335         }
336 }