*/
public CCodeLineDirective current_line { get; set; }
+ /**
+ * The current block to be written into.
+ */
+ public CCodeBlock current_block { get; set; }
+
private List<CCodeParameter> parameters = new ArrayList<CCodeParameter> ();
- CCodeBlock current_block;
List<CCodeStatement> statement_stack = new ArrayList<CCodeStatement> ();
public CCodeFunction (string name, string return_type = "void") {
public int next_temp_var_id;
public bool current_method_inner_error;
public bool current_method_return;
+ public int next_coroutine_state = 1;
public Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
public Map<string,int> closure_variable_count_map = new HashMap<string,int> (str_hash, str_equal);
public Map<LocalVariable,int> closure_variable_clash_map = new HashMap<LocalVariable,int> ();
set { emit_context.current_method_return = value; }
}
- public int next_coroutine_state = 1;
int next_block_id = 0;
Map<Block,int> block_map = new HashMap<Block,int> ();
if (expr.is_yield_expression) {
// set state before calling async function to support immediate callbacks
- int state = next_coroutine_state++;
+ int state = emit_context.next_coroutine_state++;
ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
ccode.add_expression (async_call);
if (expr.is_yield_expression) {
// set state before calling async function to support immediate callbacks
- int state = next_coroutine_state++;
+ int state = emit_context.next_coroutine_state++;
ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
ccode.add_expression (async_call);
}
}
- if (m.coroutine) {
- next_coroutine_state = 1;
- }
-
var creturn_type = m.return_type;
if (m.return_type.is_real_non_null_struct_type ()) {
// structs are returned via out parameter
push_function (function);
+ unowned CCodeBlock? co_switch_block = null;
+
// generate *_real_* functions for virtual methods
// also generate them for abstract methods of classes to prevent faulty subclassing
if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
ccode.add_case (new CCodeConstant ("0"));
ccode.add_goto ("_state_0");
- for (int state = 1; state <= m.yield_count; state++) {
- ccode.add_case (new CCodeConstant (state.to_string ()));
- ccode.add_goto ("_state_%d".printf (state));
- }
-
-
- // let gcc know that this can't happen
- ccode.add_default ();
- ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
+ co_switch_block = ccode.current_block;
ccode.close ();
if (m.body != null) {
m.body.emit (this);
+
+ if (co_switch_block != null) {
+ // after counting the number of yields for coroutines, append the case statements to the switch
+ var old_block = ccode.current_block;
+ ccode.current_block = co_switch_block;
+
+ for (int state = 1; state < emit_context.next_coroutine_state; state++) {
+ ccode.add_case (new CCodeConstant (state.to_string ()));
+ ccode.add_goto ("_state_%d".printf (state));
+ }
+
+ // let gcc know that this can't happen
+ ccode.add_default ();
+ ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
+
+ ccode.current_block = old_block;
+ co_switch_block = null;
+ }
}
// we generate the same code if we see a return statement, this handles the case without returns
}
if (stmt.yield_expression == null) {
- int state = next_coroutine_state++;
+ int state = emit_context.next_coroutine_state++;
ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
ccode.add_return (new CCodeConstant ("FALSE"));
if (bus_get_proxy_async || conn_get_proxy_async) {
if (expr.is_yield_expression) {
- int state = next_coroutine_state++;
+ int state = emit_context.next_coroutine_state++;
ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
ccode.add_expression (ccall);
asynchronous/bug659886.vala \
asynchronous/bug661961.vala \
asynchronous/bug710103.vala \
+ asynchronous/bug741929.vala \
asynchronous/bug742621.vala \
asynchronous/bug762819.vala \
asynchronous/bug777242.vala \
--- /dev/null
+MainLoop? loop = null;
+
+class Foo : Object {
+ bool running = false;
+
+ public Foo () {
+ }
+
+ public async void query_async () throws Error {
+ running = true;
+
+ try {
+ if (!yield internal_query_async ()) {
+ return;
+ }
+ } finally {
+ try {
+ yield close_query_async ();
+ } catch (Error e) {
+ // ignored
+ }
+
+ running = false;
+ }
+ }
+
+ async bool internal_query_async () throws Error {
+ return true;
+ }
+
+ async void close_query_async () throws Error {
+ }
+}
+
+async void go_async () {
+ Foo foo = new Foo ();
+ try {
+ yield foo.query_async ();
+ } catch (Error e) {
+ }
+
+ loop.quit ();
+}
+
+void main () {
+ loop = new MainLoop ();
+ go_async.begin ();
+ loop.run ();
+}
+
public bool is_async_callback { get; set; }
- public int yield_count { get; set; }
-
private List<Parameter> parameters = new ArrayList<Parameter> ();
private List<Expression> preconditions;
private List<Expression> postconditions;
error = true;
Report.error (source_reference, "yield expression not available outside async method");
}
- context.analyzer.current_method.yield_count++;
}
if (m != null && m.coroutine && !is_yield_expression && ((MemberAccess) call).member_name != "end") {
// .begin call of async method, no error can happen here
error = true;
Report.error (source_reference, "yield expression not available outside async method");
}
- context.analyzer.current_method.yield_count++;
}
// FIXME partial code duplication of MethodCall.check
error = yield_expression.error;
}
- context.analyzer.current_method.yield_count++;
-
return !error;
}