gio-2.0: Fix g_file_mount_enclosing_volume binding
[vala-lang.git] / codegen / valagerrormodule.vala
blob9d624ded918dccd018504d754d9cbac1a71998fe
1 /* valagerrormodule.vala
3 * Copyright (C) 2008-2009 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>
21 * Thijs Vermeir <thijsvermeir@gmail.com>
24 using GLib;
25 using Gee;
27 internal class Vala.GErrorModule : CCodeDelegateModule {
28 private int current_try_id = 0;
29 private int next_try_id = 0;
30 private bool is_in_catch = false;
32 public GErrorModule (CCodeGenerator codegen, CCodeModule? next) {
33 base (codegen, next);
36 public override void generate_error_domain_declaration (ErrorDomain edomain, CCodeDeclarationSpace decl_space) {
37 if (decl_space.add_symbol_declaration (edomain, edomain.get_cname ())) {
38 return;
41 var cenum = new CCodeEnum (edomain.get_cname ());
43 foreach (ErrorCode ecode in edomain.get_codes ()) {
44 if (ecode.value == null) {
45 cenum.add_value (new CCodeEnumValue (ecode.get_cname ()));
46 } else {
47 ecode.value.accept (codegen);
48 cenum.add_value (new CCodeEnumValue (ecode.get_cname (), (CCodeExpression) ecode.value.ccodenode));
52 decl_space.add_type_definition (cenum);
54 string quark_fun_name = edomain.get_lower_case_cprefix () + "quark";
56 var error_domain_define = new CCodeMacroReplacement (edomain.get_upper_case_cname (), quark_fun_name + " ()");
57 decl_space.add_type_definition (error_domain_define);
59 var cquark_fun = new CCodeFunction (quark_fun_name, gquark_type.data_type.get_cname ());
61 decl_space.add_type_member_declaration (cquark_fun);
64 public override void visit_error_domain (ErrorDomain edomain) {
65 generate_error_domain_declaration (edomain, source_declarations);
67 if (!edomain.is_internal_symbol ()) {
68 generate_error_domain_declaration (edomain, header_declarations);
70 if (!edomain.is_private_symbol ()) {
71 generate_error_domain_declaration (edomain, internal_header_declarations);
74 string quark_fun_name = edomain.get_lower_case_cprefix () + "quark";
76 var cquark_fun = new CCodeFunction (quark_fun_name, gquark_type.data_type.get_cname ());
77 var cquark_block = new CCodeBlock ();
79 var cquark_call = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
80 cquark_call.add_argument (new CCodeConstant ("\"" + edomain.get_lower_case_cname () + "-quark\""));
82 cquark_block.add_statement (new CCodeReturnStatement (cquark_call));
84 cquark_fun.block = cquark_block;
85 source_type_member_definition.append (cquark_fun);
88 public override void visit_throw_statement (ThrowStatement stmt) {
89 stmt.accept_children (codegen);
91 var cfrag = new CCodeFragment ();
93 // method will fail
94 current_method_inner_error = true;
95 var cassign = new CCodeAssignment (get_variable_cexpression ("_inner_error_"), (CCodeExpression) stmt.error_expression.ccodenode);
96 cfrag.append (new CCodeExpressionStatement (cassign));
98 head.add_simple_check (stmt, cfrag);
100 stmt.ccodenode = cfrag;
102 create_temp_decl (stmt, stmt.error_expression.temp_vars);
105 public virtual CCodeStatement return_with_exception (CCodeExpression error_expr)
107 var cpropagate = new CCodeFunctionCall (new CCodeIdentifier ("g_propagate_error"));
108 cpropagate.add_argument (new CCodeIdentifier ("error"));
109 cpropagate.add_argument (error_expr);
111 var cerror_block = new CCodeBlock ();
112 cerror_block.add_statement (new CCodeExpressionStatement (cpropagate));
114 // free local variables
115 var free_frag = new CCodeFragment ();
116 append_local_free (current_symbol, free_frag, false);
117 cerror_block.add_statement (free_frag);
119 if (current_return_type is VoidType) {
120 cerror_block.add_statement (new CCodeReturnStatement ());
121 } else {
122 cerror_block.add_statement (new CCodeReturnStatement (default_value_for_type (current_return_type, false)));
125 return cerror_block;
128 CCodeStatement uncaught_error_statement (CCodeExpression inner_error) {
129 var cerror_block = new CCodeBlock ();
131 // free local variables
132 var free_frag = new CCodeFragment ();
133 append_local_free (current_symbol, free_frag, false);
134 cerror_block.add_statement (free_frag);
136 var ccritical = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
137 ccritical.add_argument (new CCodeConstant ("\"file %s: line %d: uncaught error: %s\""));
138 ccritical.add_argument (new CCodeConstant ("__FILE__"));
139 ccritical.add_argument (new CCodeConstant ("__LINE__"));
140 ccritical.add_argument (new CCodeMemberAccess.pointer (inner_error, "message"));
142 var cclear = new CCodeFunctionCall (new CCodeIdentifier ("g_clear_error"));
143 cclear.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, inner_error));
145 var cprint_frag = new CCodeFragment ();
146 cprint_frag.append (new CCodeExpressionStatement (ccritical));
147 cprint_frag.append (new CCodeExpressionStatement (cclear));
149 // print critical message
150 cerror_block.add_statement (cprint_frag);
152 if (current_method is CreationMethod) {
153 cerror_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("NULL")));
154 } else if (current_method != null && current_method.coroutine) {
155 cerror_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
156 } else if (current_return_type is VoidType) {
157 cerror_block.add_statement (new CCodeReturnStatement ());
158 } else if (current_return_type != null) {
159 cerror_block.add_statement (new CCodeReturnStatement (default_value_for_type (current_return_type, false)));
162 return cerror_block;
165 public override void add_simple_check (CodeNode node, CCodeFragment cfrag) {
166 current_method_inner_error = true;
168 var inner_error = get_variable_cexpression ("_inner_error_");
170 CCodeStatement cerror_handler = null;
172 if (current_try != null) {
173 // surrounding try found
174 var cerror_block = new CCodeBlock ();
176 // free local variables
177 var free_frag = new CCodeFragment ();
178 append_error_free (current_symbol, free_frag, current_try);
179 cerror_block.add_statement (free_frag);
181 if (!is_in_catch) {
182 foreach (CatchClause clause in current_try.get_catch_clauses ()) {
183 // go to catch clause if error domain matches
184 var cgoto_stmt = new CCodeGotoStatement (clause.clabel_name);
186 if (clause.error_type.equals (gerror_type)) {
187 // general catch clause, this should be the last one
188 cerror_block.add_statement (cgoto_stmt);
189 break;
190 } else {
191 var catch_type = clause.error_type as ErrorType;
192 var cgoto_block = new CCodeBlock ();
193 cgoto_block.add_statement (cgoto_stmt);
195 if (catch_type.error_code != null) {
196 /* catch clause specifies a specific error code */
197 var error_match = new CCodeFunctionCall (new CCodeIdentifier ("g_error_matches"));
198 error_match.add_argument (inner_error);
199 error_match.add_argument (new CCodeIdentifier (catch_type.data_type.get_upper_case_cname ()));
200 error_match.add_argument (new CCodeIdentifier (catch_type.error_code.get_cname ()));
202 cerror_block.add_statement (new CCodeIfStatement (error_match, cgoto_block));
203 } else {
204 /* catch clause specifies a full error domain */
205 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY,
206 new CCodeMemberAccess.pointer (inner_error, "domain"), new CCodeIdentifier
207 (clause.error_type.data_type.get_upper_case_cname ()));
209 cerror_block.add_statement (new CCodeIfStatement (ccond, cgoto_block));
215 // go to finally clause if no catch clause matches
216 cerror_block.add_statement (new CCodeGotoStatement ("__finally%d".printf (current_try_id)));
218 cerror_handler = cerror_block;
219 } else if (current_method != null && current_method.get_error_types ().size > 0) {
220 // current method can fail, propagate error
221 CCodeBinaryExpression ccond = null;
223 foreach (DataType error_type in current_method.get_error_types ()) {
224 // If GLib.Error is allowed we propagate everything
225 if (error_type.equals (gerror_type)) {
226 ccond = null;
227 break;
230 // Check the allowed error domains to propagate
231 var domain_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeMemberAccess.pointer
232 (inner_error, "domain"), new CCodeIdentifier (error_type.data_type.get_upper_case_cname ()));
233 if (ccond == null) {
234 ccond = domain_check;
235 } else {
236 ccond = new CCodeBinaryExpression (CCodeBinaryOperator.OR, ccond, domain_check);
240 if (ccond == null) {
241 cerror_handler = return_with_exception (inner_error);
242 } else {
243 var cerror_block = new CCodeBlock ();
244 cerror_block.add_statement (new CCodeIfStatement (ccond,
245 return_with_exception (inner_error),
246 uncaught_error_statement (inner_error)));
247 cerror_handler = cerror_block;
249 } else {
250 cerror_handler = uncaught_error_statement (inner_error);
253 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, inner_error, new CCodeConstant ("NULL"));
254 cfrag.append (new CCodeIfStatement (ccond, cerror_handler));
257 public override void visit_try_statement (TryStatement stmt) {
258 int this_try_id = next_try_id++;
260 var old_try = current_try;
261 var old_try_id = current_try_id;
262 var old_is_in_catch = is_in_catch;
263 current_try = stmt;
264 current_try_id = this_try_id;
265 is_in_catch = true;
267 foreach (CatchClause clause in stmt.get_catch_clauses ()) {
268 clause.clabel_name = "__catch%d_%s".printf (this_try_id, clause.error_type.get_lower_case_cname ());
271 if (stmt.finally_body != null) {
272 stmt.finally_body.accept (codegen);
275 is_in_catch = false;
276 stmt.body.accept (codegen);
277 is_in_catch = true;
279 foreach (CatchClause clause in stmt.get_catch_clauses ()) {
280 clause.accept (codegen);
283 current_try = old_try;
284 current_try_id = old_try_id;
285 is_in_catch = old_is_in_catch;
287 var cfrag = new CCodeFragment ();
288 cfrag.append (stmt.body.ccodenode);
290 foreach (CatchClause clause in stmt.get_catch_clauses ()) {
291 cfrag.append (new CCodeGotoStatement ("__finally%d".printf (this_try_id)));
292 cfrag.append (clause.ccodenode);
295 cfrag.append (new CCodeLabel ("__finally%d".printf (this_try_id)));
296 if (stmt.finally_body != null) {
297 cfrag.append (stmt.finally_body.ccodenode);
300 // check for errors not handled by this try statement
301 // may be handled by outer try statements or propagated
302 add_simple_check (stmt, cfrag);
304 stmt.ccodenode = cfrag;
307 public override void visit_catch_clause (CatchClause clause) {
308 if (clause.error_variable != null) {
309 clause.error_variable.active = true;
312 current_method_inner_error = true;
314 var error_type = (ErrorType) clause.error_type;
315 if (error_type.error_domain != null) {
316 generate_error_domain_declaration (error_type.error_domain, source_declarations);
319 clause.accept_children (codegen);
321 var cfrag = new CCodeFragment ();
322 cfrag.append (new CCodeLabel (clause.clabel_name));
324 var cblock = new CCodeBlock ();
326 string variable_name;
327 if (clause.variable_name != null) {
328 variable_name = get_variable_cname (clause.variable_name);
329 } else {
330 variable_name = "__err";
333 if (current_method != null && current_method.coroutine) {
334 closure_struct.add_field ("GError *", variable_name);
335 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression (variable_name), get_variable_cexpression ("_inner_error_"))));
336 } else {
337 var cdecl = new CCodeDeclaration ("GError *");
338 cdecl.add_declarator (new CCodeVariableDeclarator (variable_name, get_variable_cexpression ("_inner_error_")));
339 cblock.add_statement (cdecl);
341 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression ("_inner_error_"), new CCodeConstant ("NULL"))));
343 cblock.add_statement (clause.body.ccodenode);
345 cfrag.append (cblock);
347 clause.ccodenode = cfrag;
350 public override void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop = false) {
351 var finally_block = (Block) null;
352 if (sym.parent_node is TryStatement) {
353 finally_block = (sym.parent_node as TryStatement).finally_body;
354 } else if (sym.parent_node is CatchClause) {
355 finally_block = (sym.parent_node.parent_node as TryStatement).finally_body;
358 if (finally_block != null) {
359 cfrag.append (finally_block.ccodenode);
362 base.append_local_free (sym, cfrag, stop_at_loop);
366 // vim:sw=8 noet