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 23using GLib; 24 25/** 26 * Represents a function declaration in the C code. 27 */ 28public 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 ("G_GNUC_INTERNAL "); 113 } 114 if (!is_declaration && CCodeModifiers.NO_INLINE in modifiers) { 115 writer.write_string ("G_GNUC_NO_INLINE "); 116 } 117 if (CCodeModifiers.STATIC in modifiers) { 118 writer.write_string ("static "); 119 } 120 if (CCodeModifiers.INLINE in modifiers) { 121 writer.write_string ("inline "); 122 } 123 writer.write_string (return_type); 124 if (is_declaration) { 125 writer.write_string (" "); 126 } else { 127 writer.write_newline (); 128 } 129 writer.write_string (name); 130 writer.write_string (" ("); 131 int param_pos_begin = (is_declaration ? return_type.char_count () + 1 : 0 ) + name.char_count () + 2; 132 133 bool has_args = (CCodeModifiers.PRINTF in modifiers || CCodeModifiers.SCANF in modifiers); 134 int i = 0; 135 int format_arg_index = -1; 136 int args_index = -1; 137 foreach (CCodeParameter param in parameters) { 138 if (i > 0) { 139 writer.write_string (","); 140 writer.write_newline (); 141 writer.write_nspaces (param_pos_begin); 142 } 143 param.write (writer); 144 if (CCodeModifiers.FORMAT_ARG in param.modifiers) { 145 format_arg_index = i; 146 } 147 if (has_args && param.ellipsis) { 148 args_index = i; 149 } else if (has_args && param.type_name == "va_list" && format_arg_index < 0) { 150 format_arg_index = i - 1; 151 } 152 i++; 153 } 154 if (i == 0) { 155 writer.write_string ("void"); 156 } 157 158 writer.write_string (")"); 159 160 if (is_declaration) { 161 if (CCodeModifiers.DEPRECATED in modifiers) { 162 writer.write_string (" G_GNUC_DEPRECATED"); 163 } 164 165 if (CCodeModifiers.PRINTF in modifiers) { 166 format_arg_index = (format_arg_index >= 0 ? format_arg_index + 1 : args_index); 167 writer.write_string (" G_GNUC_PRINTF(%d,%d)".printf (format_arg_index, args_index + 1)); 168 } else if (CCodeModifiers.SCANF in modifiers) { 169 format_arg_index = (format_arg_index >= 0 ? format_arg_index + 1 : args_index); 170 writer.write_string (" G_GNUC_SCANF(%d,%d)".printf (format_arg_index, args_index + 1)); 171 } else if (format_arg_index >= 0) { 172 writer.write_string (" G_GNUC_FORMAT(%d)".printf (format_arg_index + 1)); 173 } 174 175 if (CCodeModifiers.CONST in modifiers) { 176 writer.write_string (" G_GNUC_CONST"); 177 } 178 if (CCodeModifiers.UNUSED in modifiers) { 179 writer.write_string (" G_GNUC_UNUSED"); 180 } 181 182 if (CCodeModifiers.CONSTRUCTOR in modifiers) { 183 writer.write_string (" __attribute__((constructor))"); 184 } else if (CCodeModifiers.DESTRUCTOR in modifiers) { 185 writer.write_string (" __attribute__((destructor))"); 186 } 187 188 writer.write_string (";"); 189 } else { 190 writer.write_newline (); 191 block.write (writer); 192 writer.write_newline (); 193 } 194 writer.write_newline (); 195 } 196 197 public void add_statement (CCodeNode stmt) { 198 stmt.line = current_line; 199 current_block.add_statement (stmt); 200 } 201 202 public void open_block () { 203 statement_stack.add (current_block); 204 var parent_block = current_block; 205 206 current_block = new CCodeBlock (); 207 208 parent_block.add_statement (current_block); 209 } 210 211 public void open_if (CCodeExpression condition) { 212 statement_stack.add (current_block); 213 var parent_block = current_block; 214 215 current_block = new CCodeBlock (); 216 217 var cif = new CCodeIfStatement (condition, current_block); 218 cif.line = current_line; 219 statement_stack.add (cif); 220 221 parent_block.add_statement (cif); 222 } 223 224 public void add_else () { 225 current_block = new CCodeBlock (); 226 227 var cif = (CCodeIfStatement) statement_stack[statement_stack.size - 1]; 228 cif.line = current_line; 229 assert (cif.false_statement == null); 230 cif.false_statement = current_block; 231 } 232 233 public void else_if (CCodeExpression condition) { 234 var parent_if = (CCodeIfStatement) statement_stack.remove_at (statement_stack.size - 1); 235 assert (parent_if.false_statement == null); 236 237 current_block = new CCodeBlock (); 238 239 var cif = new CCodeIfStatement (condition, current_block); 240 cif.line = current_line; 241 parent_if.false_statement = cif; 242 statement_stack.add (cif); 243 } 244 245 public void open_while (CCodeExpression condition) { 246 statement_stack.add (current_block); 247 var parent_block = current_block; 248 249 current_block = new CCodeBlock (); 250 251 var cwhile = new CCodeWhileStatement (condition, current_block); 252 cwhile.line = current_line; 253 parent_block.add_statement (cwhile); 254 } 255 256 public void open_for (CCodeExpression? initializer, CCodeExpression condition, CCodeExpression? iterator) { 257 statement_stack.add (current_block); 258 var parent_block = current_block; 259 260 current_block = new CCodeBlock (); 261 262 var cfor = new CCodeForStatement (condition, current_block); 263 cfor.line = current_line; 264 if (initializer != null) { 265 cfor.add_initializer (initializer); 266 } 267 if (iterator != null) { 268 cfor.add_iterator (iterator); 269 } 270 271 parent_block.add_statement (cfor); 272 } 273 274 public void open_switch (CCodeExpression expression) { 275 statement_stack.add (current_block); 276 var parent_block = current_block; 277 278 var cswitch = new CCodeSwitchStatement (expression); 279 cswitch.line = current_line; 280 current_block = cswitch; 281 282 parent_block.add_statement (cswitch); 283 } 284 285 public void add_label (string label) { 286 add_statement (new CCodeLabel (label)); 287 } 288 289 public void add_case (CCodeExpression expression) { 290 add_statement (new CCodeCaseStatement (expression)); 291 } 292 293 public void add_default () { 294 add_statement (new CCodeLabel ("default")); 295 } 296 297 public void add_goto (string target) { 298 add_statement (new CCodeGotoStatement (target)); 299 } 300 301 public void add_expression (CCodeExpression expression) { 302 add_statement (new CCodeExpressionStatement (expression)); 303 } 304 305 public void add_assignment (CCodeExpression left, CCodeExpression right) { 306 add_expression (new CCodeAssignment (left, right)); 307 } 308 309 public void add_return (CCodeExpression? expression = null) { 310 add_statement (new CCodeReturnStatement (expression)); 311 } 312 313 public void add_break () { 314 add_statement (new CCodeBreakStatement ()); 315 } 316 317 public void add_continue () { 318 add_statement (new CCodeContinueStatement ()); 319 } 320 321 public void add_declaration (string type_name, CCodeDeclarator declarator, CCodeModifiers modifiers = 0) { 322 var stmt = new CCodeDeclaration (type_name); 323 stmt.add_declarator (declarator); 324 stmt.modifiers = modifiers; 325 add_statement (stmt); 326 } 327 328 public void close () { 329 do { 330 var top = statement_stack.remove_at (statement_stack.size - 1); 331 current_block = top as CCodeBlock; 332 } while (current_block == null); 333 } 334} 335