codegen: Fix floating reference regression with Variants
[vala-gnome.git] / ccode / valaccodefunction.vala
blob688c6d1eb420103c9580f6b5af559e8692312d29
1 /* valaccodefunction.vala
3 * Copyright (C) 2006-2012 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 using GLib;
25 /**
26 * Represents a function declaration in the C code.
28 public class Vala.CCodeFunction : CCodeNode {
29 /**
30 * The name of this function.
32 public string name { get; set; }
34 /**
35 * The function return type.
37 public string return_type { get; set; }
39 public bool is_declaration { get; set; }
41 /**
42 * The function body.
44 public CCodeBlock block { get; set; }
46 /**
47 * The current line directive.
49 public CCodeLineDirective current_line { get; set; }
51 /**
52 * The current block to be written into.
54 public CCodeBlock current_block { get; set; }
56 private List<CCodeParameter> parameters = new ArrayList<CCodeParameter> ();
58 List<CCodeStatement> statement_stack = new ArrayList<CCodeStatement> ();
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;
67 /**
68 * Appends the specified parameter to the list of function parameters.
70 * @param param a formal parameter
72 public void add_parameter (CCodeParameter param) {
73 parameters.add (param);
76 public void insert_parameter (int position, CCodeParameter param) {
77 parameters.insert (position, param);
80 public int get_parameter_count () {
81 return parameters.size;
84 public CCodeParameter get_parameter (int position) {
85 return parameters[position];
88 /**
89 * Returns a copy of this function.
91 * @return copied function
93 public CCodeFunction copy () {
94 var func = new CCodeFunction (name, return_type);
95 func.modifiers = modifiers;
97 /* no deep copy for lists available yet
98 * func.parameters = parameters.copy ();
100 foreach (CCodeParameter param in parameters) {
101 func.parameters.add (param);
104 func.is_declaration = is_declaration;
105 func.block = block;
106 return func;
109 public override void write (CCodeWriter writer) {
110 writer.write_indent (line);
111 if (CCodeModifiers.INTERNAL in modifiers) {
112 writer.write_string ("G_GNUC_INTERNAL ");
114 if (CCodeModifiers.STATIC in modifiers) {
115 writer.write_string ("static ");
117 if (CCodeModifiers.INLINE in modifiers) {
118 writer.write_string ("inline ");
120 writer.write_string (return_type);
121 if (is_declaration) {
122 writer.write_string (" ");
123 } else {
124 writer.write_newline ();
126 writer.write_string (name);
127 writer.write_string (" (");
128 int param_pos_begin = (is_declaration ? return_type.char_count () + 1 : 0 ) + name.char_count () + 2;
130 bool has_args = (CCodeModifiers.PRINTF in modifiers || CCodeModifiers.SCANF in modifiers);
131 int i = 0;
132 int format_arg_index = -1;
133 int args_index = -1;
134 foreach (CCodeParameter param in parameters) {
135 if (i > 0) {
136 writer.write_string (",");
137 writer.write_newline ();
138 writer.write_nspaces (param_pos_begin);
140 param.write (writer);
141 if (CCodeModifiers.FORMAT_ARG in param.modifiers) {
142 format_arg_index = i;
144 if (has_args && param.ellipsis) {
145 args_index = i;
146 } else if (has_args && param.type_name == "va_list" && format_arg_index < 0) {
147 format_arg_index = i - 1;
149 i++;
151 if (i == 0) {
152 writer.write_string ("void");
155 writer.write_string (")");
157 if (is_declaration) {
158 if (CCodeModifiers.DEPRECATED in modifiers) {
159 writer.write_string (" G_GNUC_DEPRECATED");
162 if (CCodeModifiers.PRINTF in modifiers) {
163 format_arg_index = (format_arg_index >= 0 ? format_arg_index + 1 : args_index);
164 writer.write_string (" G_GNUC_PRINTF(%d,%d)".printf (format_arg_index, args_index + 1));
165 } else if (CCodeModifiers.SCANF in modifiers) {
166 format_arg_index = (format_arg_index >= 0 ? format_arg_index + 1 : args_index);
167 writer.write_string (" G_GNUC_SCANF(%d,%d)".printf (format_arg_index, args_index + 1));
168 } else if (format_arg_index >= 0) {
169 writer.write_string (" G_GNUC_FORMAT(%d)".printf (format_arg_index + 1));
172 if (CCodeModifiers.CONST in modifiers) {
173 writer.write_string (" G_GNUC_CONST");
175 if (CCodeModifiers.UNUSED in modifiers) {
176 writer.write_string (" G_GNUC_UNUSED");
179 if (CCodeModifiers.CONSTRUCTOR in modifiers) {
180 writer.write_string (" __attribute__((constructor))");
181 } else if (CCodeModifiers.DESTRUCTOR in modifiers) {
182 writer.write_string (" __attribute__((destructor))");
185 writer.write_string (";");
186 } else {
187 writer.write_newline ();
188 block.write (writer);
189 writer.write_newline ();
191 writer.write_newline ();
194 public void add_statement (CCodeNode stmt) {
195 stmt.line = current_line;
196 current_block.add_statement (stmt);
199 public void open_block () {
200 statement_stack.add (current_block);
201 var parent_block = current_block;
203 current_block = new CCodeBlock ();
205 parent_block.add_statement (current_block);
208 public void open_if (CCodeExpression condition) {
209 statement_stack.add (current_block);
210 var parent_block = current_block;
212 current_block = new CCodeBlock ();
214 var cif = new CCodeIfStatement (condition, current_block);
215 cif.line = current_line;
216 statement_stack.add (cif);
218 parent_block.add_statement (cif);
221 public void add_else () {
222 current_block = new CCodeBlock ();
224 var cif = (CCodeIfStatement) statement_stack[statement_stack.size - 1];
225 cif.line = current_line;
226 assert (cif.false_statement == null);
227 cif.false_statement = current_block;
230 public void else_if (CCodeExpression condition) {
231 var parent_if = (CCodeIfStatement) statement_stack.remove_at (statement_stack.size - 1);
232 assert (parent_if.false_statement == null);
234 current_block = new CCodeBlock ();
236 var cif = new CCodeIfStatement (condition, current_block);
237 cif.line = current_line;
238 parent_if.false_statement = cif;
239 statement_stack.add (cif);
242 public void open_while (CCodeExpression condition) {
243 statement_stack.add (current_block);
244 var parent_block = current_block;
246 current_block = new CCodeBlock ();
248 var cwhile = new CCodeWhileStatement (condition, current_block);
249 cwhile.line = current_line;
250 parent_block.add_statement (cwhile);
253 public void open_for (CCodeExpression? initializer, CCodeExpression condition, CCodeExpression? iterator) {
254 statement_stack.add (current_block);
255 var parent_block = current_block;
257 current_block = new CCodeBlock ();
259 var cfor = new CCodeForStatement (condition, current_block);
260 cfor.line = current_line;
261 if (initializer != null) {
262 cfor.add_initializer (initializer);
264 if (iterator != null) {
265 cfor.add_iterator (iterator);
268 parent_block.add_statement (cfor);
271 public void open_switch (CCodeExpression expression) {
272 statement_stack.add (current_block);
273 var parent_block = current_block;
275 var cswitch = new CCodeSwitchStatement (expression);
276 cswitch.line = current_line;
277 current_block = cswitch;
279 parent_block.add_statement (cswitch);
282 public void add_label (string label) {
283 add_statement (new CCodeLabel (label));
286 public void add_case (CCodeExpression expression) {
287 add_statement (new CCodeCaseStatement (expression));
290 public void add_default () {
291 add_statement (new CCodeLabel ("default"));
294 public void add_goto (string target) {
295 add_statement (new CCodeGotoStatement (target));
298 public void add_expression (CCodeExpression expression) {
299 add_statement (new CCodeExpressionStatement (expression));
302 public void add_assignment (CCodeExpression left, CCodeExpression right) {
303 add_expression (new CCodeAssignment (left, right));
306 public void add_return (CCodeExpression? expression = null) {
307 add_statement (new CCodeReturnStatement (expression));
310 public void add_break () {
311 add_statement (new CCodeBreakStatement ());
314 public void add_continue () {
315 add_statement (new CCodeContinueStatement ());
318 public void add_declaration (string type_name, CCodeDeclarator declarator, CCodeModifiers modifiers = 0) {
319 var stmt = new CCodeDeclaration (type_name);
320 stmt.add_declarator (declarator);
321 stmt.modifiers = modifiers;
322 add_statement (stmt);
325 public void close () {
326 do {
327 var top = statement_stack.remove_at (statement_stack.size - 1);
328 current_block = top as CCodeBlock;
329 } while (current_block == null);