public override void return_with_exception(CCodeExpression error_expr) { if (!is_in_coroutine()) { base.return_with_exception(error_expr); return; } var async_result_expr = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), "_async_result"); CCodeFunctionCall set_error = null; set_error = new CCodeFunctionCall(new CCodeIdentifier("g_task_return_error")); set_error.add_argument(async_result_expr); set_error.add_argument(error_expr); ccode.add_expression(set_error); append_local_free(current_symbol, false); // We already returned the error above, we must not return anything else here. var unref = new CCodeFunctionCall(new CCodeIdentifier("g_object_unref")); unref.add_argument(async_result_expr); ccode.add_expression(unref); ccode.add_return(new CCodeConstant("FALSE")); }
CCodeExpression get_array_length(CCodeExpression expr, int dim) { var id = expr as CCodeIdentifier; var ma = expr as CCodeMemberAccess; if (id != null) { return(new CCodeIdentifier("%s_length%d".printf(id.name, dim))); } else if (ma != null) { if (ma.is_pointer) { return(CCodeMemberAccess.pointer(ma.inner, "%s_length%d".printf(ma.member_name, dim))); } else { return(new CCodeMemberAccess(ma.inner, "%s_length%d".printf(ma.member_name, dim))); } } else { // must be NULL-terminated var len_call = new CCodeFunctionCall(new CCodeIdentifier("g_strv_length")); len_call.add_argument(expr); return(len_call); } }
void uncaught_error_statement(CCodeExpression inner_error, bool unexpected = false) { // free local variables append_local_free(current_symbol, false); var ccritical = new CCodeFunctionCall(new CCodeIdentifier("g_critical")); ccritical.add_argument(new CCodeConstant(unexpected ? "\"file %s: line %d: unexpected error: %s (%s, %d)\"" : "\"file %s: line %d: uncaught error: %s (%s, %d)\"")); ccritical.add_argument(new CCodeConstant("__FILE__")); ccritical.add_argument(new CCodeConstant("__LINE__")); ccritical.add_argument(CCodeMemberAccess.pointer(inner_error, "message")); var domain_name = new CCodeFunctionCall(new CCodeIdentifier("g_quark_to_string")); domain_name.add_argument(CCodeMemberAccess.pointer(inner_error, "domain")); ccritical.add_argument(domain_name); ccritical.add_argument(CCodeMemberAccess.pointer(inner_error, "code")); var cclear = new CCodeFunctionCall(new CCodeIdentifier("g_clear_error")); cclear.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, inner_error)); // print critical message ccode.add_expression(ccritical); ccode.add_expression(cclear); if (is_in_constructor() || is_in_destructor()) { // just print critical, do not return prematurely } else if (current_method is CreationMethod) { if (current_method.parent_symbol is Struct) { ccode.add_return(); } else { ccode.add_return(new CCodeConstant("NULL")); } } else if (is_in_coroutine()) { var async_result_expr = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), "_async_result"); var unref = new CCodeFunctionCall(new CCodeIdentifier("g_object_unref")); unref.add_argument(async_result_expr); ccode.add_expression(unref); ccode.add_return(new CCodeConstant("FALSE")); } else if (current_return_type != null) { return_default_value(current_return_type); } }
void generate_async_ready_callback_wrapper(Method m, string function_name) { var function = new CCodeFunction(function_name, "void"); function.modifiers = CCodeModifiers.STATIC; function.add_parameter(new CCodeParameter("*source_object", "GObject")); function.add_parameter(new CCodeParameter("*res", "GAsyncResult")); function.add_parameter(new CCodeParameter("*user_data", "void")); push_function(function); // Set _task_complete_ to false after calling back to the real func var async_result_cast = new CCodeFunctionCall(new CCodeIdentifier("G_TASK")); async_result_cast.add_argument(new CCodeIdentifier("res")); var dataname = Symbol.lower_case_to_camel_case(get_ccode_name(m)) + "Data"; ccode.add_declaration(dataname + "*", new CCodeVariableDeclarator("_task_data_")); var get_data_call = new CCodeFunctionCall(new CCodeIdentifier("g_task_get_task_data")); get_data_call.add_argument(async_result_cast); var data_var = new CCodeIdentifier("_task_data_"); ccode.add_assignment(data_var, get_data_call); var task_inner_callback = CCodeMemberAccess.pointer(data_var, "_callback_"); var callback_is_nonnull = new CCodeBinaryExpression(CCodeBinaryOperator.INEQUALITY, task_inner_callback, new CCodeConstant("NULL")); ccode.open_if(callback_is_nonnull); var nested_callback = new CCodeFunctionCall(task_inner_callback); nested_callback.add_argument(new CCodeIdentifier("source_object")); nested_callback.add_argument(new CCodeIdentifier("res")); nested_callback.add_argument(new CCodeIdentifier("user_data")); ccode.add_expression(nested_callback); ccode.close(); ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "_task_complete_"), new CCodeConstant("TRUE")); pop_function(); cfile.add_function_declaration(function); cfile.add_function(function); }
public override string generate_ready_function(Method m) { // generate ready callback handler var dataname = Symbol.lower_case_to_camel_case(get_ccode_name(m)) + "Data"; var readyfunc = new CCodeFunction(get_ccode_name(m) + "_ready", "void"); if (!add_wrapper(readyfunc.name)) { // wrapper already defined return(readyfunc.name); } readyfunc.add_parameter(new CCodeParameter("source_object", "GObject*")); readyfunc.add_parameter(new CCodeParameter("_res_", "GAsyncResult*")); readyfunc.add_parameter(new CCodeParameter("_user_data_", "gpointer")); push_function(readyfunc); var data_var = new CCodeIdentifier("_data_"); ccode.add_declaration(dataname + "*", new CCodeVariableDeclarator("_data_")); ccode.add_assignment(data_var, new CCodeIdentifier("_user_data_")); ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "_source_object_"), new CCodeIdentifier("source_object")); ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "_res_"), new CCodeIdentifier("_res_")); if (!context.require_glib_version(2, 44)) { ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "_task_complete_"), new CCodeConstant("TRUE")); } var ccall = new CCodeFunctionCall(new CCodeIdentifier(get_ccode_real_name(m) + "_co")); ccall.add_argument(data_var); ccode.add_expression(ccall); readyfunc.modifiers |= CCodeModifiers.STATIC; pop_function(); cfile.add_function_declaration(readyfunc); cfile.add_function(readyfunc); return(readyfunc.name); }
public override void visit_yield_statement(YieldStatement stmt) { if (!is_in_coroutine()) { return; } if (stmt.yield_expression == null) { int state = emit_context.next_coroutine_state++; ccode.add_assignment(CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), "_state_"), new CCodeConstant(state.ToString())); ccode.add_return(new CCodeConstant("FALSE")); ccode.add_label("_state_%d".printf(state)); ccode.add_statement(new CCodeEmptyStatement()); return; } if (stmt.yield_expression.error) { stmt.error = true; return; } ccode.add_expression(get_cvalue(stmt.yield_expression)); if (stmt.tree_can_fail && stmt.yield_expression.tree_can_fail) { // simple case, no node breakdown necessary add_simple_check(stmt.yield_expression); } /* free temporary objects */ foreach (var value in temp_ref_values) { ccode.add_expression(destroy_value(value)); } temp_ref_values.Clear(); }
public override void visit_member_access(MemberAccess expr) { if (expr.symbol_reference is Signal) { CCodeExpression pub_inst = null; if (expr.inner != null) { pub_inst = get_cvalue(expr.inner); } var sig = (Signal)expr.symbol_reference; var cl = (TypeSymbol)sig.parent_symbol; if (expr.inner is BaseAccess && sig.is_virtual) { var m = sig.default_handler; var base_class = (Class)m.parent_symbol; var vcast = new CCodeFunctionCall(new CCodeIdentifier("%s_CLASS".printf(get_ccode_upper_case_name(base_class, null)))); vcast.add_argument(new CCodeIdentifier("%s_parent_class".printf(get_ccode_lower_case_name(current_class)))); set_cvalue(expr, CCodeMemberAccess.pointer(vcast, m.name)); return; } if (!sig.external_package && expr.source_reference.file == sig.source_reference.file) { var ccall = new CCodeFunctionCall(new CCodeIdentifier("g_signal_emit")); ccall.add_argument(pub_inst); ccall.add_argument(get_signal_id_cexpression(sig)); ccall.add_argument(new CCodeConstant("0")); set_cvalue(expr, ccall); } else if (get_signal_has_emitter(sig)) { string emitter_func; if (sig.emitter != null) { if (!sig.external_package && expr.source_reference.file != sig.source_reference.file) { generate_method_declaration(sig.emitter, cfile); } emitter_func = get_ccode_lower_case_name(sig.emitter); } else { emitter_func = "%s_%s".printf(get_ccode_lower_case_name(cl), get_ccode_lower_case_name(sig)); } var ccall = new CCodeFunctionCall(new CCodeIdentifier(emitter_func)); ccall.add_argument(pub_inst); set_cvalue(expr, ccall); } else { var ccall = new CCodeFunctionCall(new CCodeIdentifier("g_signal_emit_by_name")); ccall.add_argument(pub_inst); ccall.add_argument(get_signal_canonical_constant(sig)); set_cvalue(expr, ccall); } } else { base.visit_member_access(expr); } }
public override void visit_constructor(Constructor c) { push_line(c.source_reference); var cl = (Class)c.parent_symbol; if (c.binding == MemberBinding.INSTANCE) { if (!cl.is_subtype_of(gobject_type)) { Report.error(c.source_reference, "construct blocks require GLib.Object"); c.error = true; return; } push_context(new EmitContext(c)); var function = new CCodeFunction("%s_constructor".printf(get_ccode_lower_case_name(cl, null)), "GObject *"); function.modifiers = CCodeModifiers.STATIC; function.add_parameter(new CCodeParameter("type", "GType")); function.add_parameter(new CCodeParameter("n_construct_properties", "guint")); function.add_parameter(new CCodeParameter("construct_properties", "GObjectConstructParam *")); cfile.add_function_declaration(function); push_function(function); ccode.add_declaration("GObject *", new CCodeVariableDeclarator("obj")); ccode.add_declaration("GObjectClass *", new CCodeVariableDeclarator("parent_class")); var ccast = new CCodeFunctionCall(new CCodeIdentifier("G_OBJECT_CLASS")); ccast.add_argument(new CCodeIdentifier("%s_parent_class".printf(get_ccode_lower_case_name(cl, null)))); ccode.add_assignment(new CCodeIdentifier("parent_class"), ccast); var ccall = new CCodeFunctionCall(CCodeMemberAccess.pointer(new CCodeIdentifier("parent_class"), "constructor")); ccall.add_argument(new CCodeIdentifier("type")); ccall.add_argument(new CCodeIdentifier("n_construct_properties")); ccall.add_argument(new CCodeIdentifier("construct_properties")); ccode.add_assignment(new CCodeIdentifier("obj"), ccall); ccall = generate_instance_cast(new CCodeIdentifier("obj"), cl); ccode.add_declaration("%s *".printf(get_ccode_name(cl)), new CCodeVariableDeclarator("self")); ccode.add_assignment(new CCodeIdentifier("self"), ccall); c.body.emit(this); if (current_method_inner_error) { /* always separate error parameter and inner_error local variable * as error may be set to NULL but we're always interested in inner errors */ ccode.add_declaration("GError *", CCodeVariableDeclarator.zero("_inner_error_", new CCodeConstant("NULL"))); } ccode.add_return(new CCodeIdentifier("obj")); pop_function(); cfile.add_function(function); pop_context(); } else if (c.binding == MemberBinding.CLASS) { // class constructor if (cl.is_compact) { Report.error(c.source_reference, "class constructors are not supported in compact classes"); c.error = true; return; } push_context(base_init_context); c.body.emit(this); if (current_method_inner_error) { /* always separate error parameter and inner_error local variable * as error may be set to NULL but we're always interested in inner errors */ ccode.add_declaration("GError *", CCodeVariableDeclarator.zero("_inner_error_", new CCodeConstant("NULL"))); } pop_context(); } else if (c.binding == MemberBinding.STATIC) { // static class constructor // add to class_init if (cl.is_compact) { Report.error(c.source_reference, "static constructors are not supported in compact classes"); c.error = true; return; } push_context(class_init_context); c.body.emit(this); if (current_method_inner_error) { /* always separate error parameter and inner_error local variable * as error may be set to NULL but we're always interested in inner errors */ ccode.add_declaration("GError *", CCodeVariableDeclarator.zero("_inner_error_", new CCodeConstant("NULL"))); } pop_context(); } else { Report.error(c.source_reference, "internal error: constructors must have instance, class, or static binding"); } pop_line(); }
public override void generate_class_init(Class cl) { if (!cl.is_subtype_of(gobject_type)) { return; } /* set property handlers */ var ccall = new CCodeFunctionCall(new CCodeIdentifier("G_OBJECT_CLASS")); ccall.add_argument(new CCodeIdentifier("klass")); if (class_has_readable_properties(cl) || cl.get_type_parameters().Count > 0) { ccode.add_assignment(CCodeMemberAccess.pointer(ccall, "get_property"), new CCodeIdentifier("_vala_%s_get_property".printf(get_ccode_lower_case_name(cl, null)))); } if (class_has_writable_properties(cl) || cl.get_type_parameters().Count > 0) { ccode.add_assignment(CCodeMemberAccess.pointer(ccall, "set_property"), new CCodeIdentifier("_vala_%s_set_property".printf(get_ccode_lower_case_name(cl, null)))); } /* set constructor */ if (cl.constructor != null) { var ccast = new CCodeFunctionCall(new CCodeIdentifier("G_OBJECT_CLASS")); ccast.add_argument(new CCodeIdentifier("klass")); ccode.add_assignment(CCodeMemberAccess.pointer(ccast, "constructor"), new CCodeIdentifier("%s_constructor".printf(get_ccode_lower_case_name(cl, null)))); } /* set finalize function */ if (cl.get_fields().Count > 0 || cl.destructor != null) { var ccast = new CCodeFunctionCall(new CCodeIdentifier("G_OBJECT_CLASS")); ccast.add_argument(new CCodeIdentifier("klass")); ccode.add_assignment(CCodeMemberAccess.pointer(ccast, "finalize"), new CCodeIdentifier("%s_finalize".printf(get_ccode_lower_case_name(cl, null)))); } /* create type, dup_func, and destroy_func properties for generic types */ foreach (TypeParameter type_param in cl.get_type_parameters()) { string func_name, enum_value; CCodeConstant func_name_constant; CCodeFunctionCall cinst, cspec; var name_prefix = type_param.name.ToLower(); var canonical_prefix = name_prefix.Replace("_", "-"); func_name = "%s_type".printf(name_prefix); func_name_constant = new CCodeConstant("\"%s-type\"".printf(canonical_prefix)); enum_value = "%s_%s".printf(get_ccode_lower_case_name(cl, null), func_name).ToUpper(); cinst = new CCodeFunctionCall(new CCodeIdentifier("g_object_class_install_property")); cinst.add_argument(ccall); cinst.add_argument(new CCodeConstant(enum_value)); cspec = new CCodeFunctionCall(new CCodeIdentifier("g_param_spec_gtype")); cspec.add_argument(func_name_constant); cspec.add_argument(new CCodeConstant("\"type\"")); cspec.add_argument(new CCodeConstant("\"type\"")); cspec.add_argument(new CCodeIdentifier("G_TYPE_NONE")); cspec.add_argument(new CCodeConstant("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY")); cinst.add_argument(cspec); ccode.add_expression(cinst); prop_enum.add_value(new CCodeEnumValue(enum_value)); func_name = "%s_dup_func".printf(name_prefix); func_name_constant = new CCodeConstant("\"%s-dup-func\"".printf(canonical_prefix)); enum_value = "%s_%s".printf(get_ccode_lower_case_name(cl, null), func_name).ToUpper(); cinst = new CCodeFunctionCall(new CCodeIdentifier("g_object_class_install_property")); cinst.add_argument(ccall); cinst.add_argument(new CCodeConstant(enum_value)); cspec = new CCodeFunctionCall(new CCodeIdentifier("g_param_spec_pointer")); cspec.add_argument(func_name_constant); cspec.add_argument(new CCodeConstant("\"dup func\"")); cspec.add_argument(new CCodeConstant("\"dup func\"")); cspec.add_argument(new CCodeConstant("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY")); cinst.add_argument(cspec); ccode.add_expression(cinst); prop_enum.add_value(new CCodeEnumValue(enum_value)); func_name = "%s_destroy_func".printf(name_prefix); func_name_constant = new CCodeConstant("\"%s-destroy-func\"".printf(canonical_prefix)); enum_value = "%s_%s".printf(get_ccode_lower_case_name(cl, null), func_name).ToUpper(); cinst = new CCodeFunctionCall(new CCodeIdentifier("g_object_class_install_property")); cinst.add_argument(ccall); cinst.add_argument(new CCodeConstant(enum_value)); cspec = new CCodeFunctionCall(new CCodeIdentifier("g_param_spec_pointer")); cspec.add_argument(func_name_constant); cspec.add_argument(new CCodeConstant("\"destroy func\"")); cspec.add_argument(new CCodeConstant("\"destroy func\"")); cspec.add_argument(new CCodeConstant("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY")); cinst.add_argument(cspec); ccode.add_expression(cinst); prop_enum.add_value(new CCodeEnumValue(enum_value)); } /* create properties */ var props = cl.get_properties(); foreach (Property prop in props) { if (!is_gobject_property(prop)) { continue; } if (prop.comment != null) { ccode.add_statement(new CCodeComment(prop.comment.content)); } var cinst = new CCodeFunctionCall(new CCodeIdentifier("g_object_class_install_property")); cinst.add_argument(ccall); cinst.add_argument(new CCodeConstant(get_ccode_upper_case_name(prop))); cinst.add_argument(get_param_spec(prop)); ccode.add_expression(cinst); } }
private void add_set_property_function(Class cl) { var set_prop = new CCodeFunction("_vala_%s_set_property".printf(get_ccode_lower_case_name(cl, null)), "void"); set_prop.modifiers = CCodeModifiers.STATIC; set_prop.add_parameter(new CCodeParameter("object", "GObject *")); set_prop.add_parameter(new CCodeParameter("property_id", "guint")); set_prop.add_parameter(new CCodeParameter("value", "const GValue *")); set_prop.add_parameter(new CCodeParameter("pspec", "GParamSpec *")); push_function(set_prop); CCodeFunctionCall ccall = generate_instance_cast(new CCodeIdentifier("object"), cl); ccode.add_declaration("%s *".printf(get_ccode_name(cl)), new CCodeVariableDeclarator("self", ccall)); ccode.open_switch(new CCodeIdentifier("property_id")); var props = cl.get_properties(); foreach (Property prop in props) { if (prop.set_accessor == null || prop.is_abstract) { continue; } if (!is_gobject_property(prop)) { continue; } Property base_prop = prop; CCodeExpression cself = new CCodeIdentifier("self"); if (prop.base_property != null) { var base_type = (Class)prop.base_property.parent_symbol; base_prop = prop.base_property; cself = get_cvalue_(transform_value(new GLibValue(new ObjectType(cl), cself, true), new ObjectType(base_type), prop)); generate_property_accessor_declaration(prop.base_property.set_accessor, cfile); } else if (prop.base_interface_property != null) { var base_type = (Interface)prop.base_interface_property.parent_symbol; base_prop = prop.base_interface_property; cself = get_cvalue_(transform_value(new GLibValue(new ObjectType(cl), cself, true), new ObjectType(base_type), prop)); generate_property_accessor_declaration(prop.base_interface_property.set_accessor, cfile); } CCodeExpression cfunc; if (!get_ccode_no_accessor_method(base_prop) && !get_ccode_concrete_accessor(base_prop)) { cfunc = new CCodeIdentifier(get_ccode_name(base_prop.set_accessor)); } else { // use the static real function as helper cfunc = new CCodeIdentifier(get_ccode_real_name(prop.set_accessor)); } ccode.add_case(new CCodeIdentifier(get_ccode_upper_case_name(prop))); ccall = new CCodeFunctionCall(cfunc); ccall.add_argument(cself); if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.data_type == string_type.data_type) { ccode.open_block(); ccode.add_declaration("gpointer", new CCodeVariableDeclarator("boxed")); var cgetcall = new CCodeFunctionCall(new CCodeIdentifier("g_value_get_boxed")); cgetcall.add_argument(new CCodeIdentifier("value")); ccode.add_assignment(new CCodeIdentifier("boxed"), cgetcall); ccall.add_argument(new CCodeIdentifier("boxed")); var cisnull = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, new CCodeIdentifier("boxed"), new CCodeConstant("NULL")); var cstrvlen = new CCodeFunctionCall(new CCodeIdentifier("g_strv_length")); cstrvlen.add_argument(new CCodeIdentifier("boxed")); var ccond = new CCodeConditionalExpression(cisnull, new CCodeConstant("0"), cstrvlen); ccall.add_argument(ccond); add_guarded_expression(prop, ccall); ccode.close(); } else { var cgetcall = new CCodeFunctionCall(); if (prop.property_type.data_type != null) { cgetcall.call = new CCodeIdentifier(get_ccode_get_value_function(prop.property_type.data_type)); } else { cgetcall.call = new CCodeIdentifier("g_value_get_pointer"); } cgetcall.add_argument(new CCodeIdentifier("value")); ccall.add_argument(cgetcall); add_guarded_expression(prop, ccall); } ccode.add_break(); } /* type, dup func, and destroy func properties for generic types */ foreach (TypeParameter type_param in cl.get_type_parameters()) { string func_name, enum_value; CCodeMemberAccess cfield; CCodeFunctionCall cgetcall; func_name = "%s_type".printf(type_param.name.ToLower()); enum_value = "%s_%s".printf(get_ccode_lower_case_name(cl, null), func_name).ToUpper(); ccode.add_case(new CCodeIdentifier(enum_value)); cfield = CCodeMemberAccess.pointer(CCodeMemberAccess.pointer(new CCodeIdentifier("self"), "priv"), func_name); cgetcall = new CCodeFunctionCall(new CCodeIdentifier("g_value_get_gtype")); cgetcall.add_argument(new CCodeIdentifier("value")); ccode.add_assignment(cfield, cgetcall); ccode.add_break(); func_name = "%s_dup_func".printf(type_param.name.ToLower()); enum_value = "%s_%s".printf(get_ccode_lower_case_name(cl, null), func_name).ToUpper(); ccode.add_case(new CCodeIdentifier(enum_value)); cfield = CCodeMemberAccess.pointer(CCodeMemberAccess.pointer(new CCodeIdentifier("self"), "priv"), func_name); cgetcall = new CCodeFunctionCall(new CCodeIdentifier("g_value_get_pointer")); cgetcall.add_argument(new CCodeIdentifier("value")); ccode.add_assignment(cfield, cgetcall); ccode.add_break(); func_name = "%s_destroy_func".printf(type_param.name.ToLower()); enum_value = "%s_%s".printf(get_ccode_lower_case_name(cl, null), func_name).ToUpper(); ccode.add_case(new CCodeIdentifier(enum_value)); cfield = CCodeMemberAccess.pointer(CCodeMemberAccess.pointer(new CCodeIdentifier("self"), "priv"), func_name); cgetcall = new CCodeFunctionCall(new CCodeIdentifier("g_value_get_pointer")); cgetcall.add_argument(new CCodeIdentifier("value")); ccode.add_assignment(cfield, cgetcall); ccode.add_break(); } ccode.add_default(); emit_invalid_property_id_warn(); ccode.add_break(); ccode.close(); pop_function(); cfile.add_function_declaration(set_prop); cfile.add_function(set_prop); }
public override void visit_foreach_statement(ForeachStatement stmt) { ccode.open_block(); var collection_backup = stmt.collection_variable; var collection_type = collection_backup.variable_type; var array_type = collection_type as ArrayType; if (array_type != null) { // avoid assignment issues array_type.inline_allocated = false; array_type.fixed_length = false; } visit_local_variable(collection_backup); ccode.add_assignment(get_variable_cexpression(get_local_cname(collection_backup)), get_cvalue(stmt.collection)); if (stmt.tree_can_fail && stmt.collection.tree_can_fail) { // exception handling add_simple_check(stmt.collection); } if (stmt.collection.value_type is ArrayType) { array_type = (ArrayType)stmt.collection.value_type; var array_len = get_array_length_cexpression(stmt.collection); // store array length for use by _vala_array_free ccode.add_assignment(get_variable_cexpression(get_array_length_cname(get_local_cname(collection_backup), 1)), array_len); var iterator_variable = new LocalVariable(int_type.copy(), stmt.variable_name + "_it"); visit_local_variable(iterator_variable); var it_name = get_local_cname(iterator_variable); var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.LESS_THAN, get_variable_cexpression(it_name), array_len); ccode.open_for(new CCodeAssignment(get_variable_cexpression(it_name), new CCodeConstant("0")), ccond, new CCodeAssignment(get_variable_cexpression(it_name), new CCodeBinaryExpression(CCodeBinaryOperator.PLUS, get_variable_cexpression(it_name), new CCodeConstant("1")))); CCodeExpression element_expr = new CCodeElementAccess(get_variable_cexpression(get_local_cname(collection_backup)), get_variable_cexpression(it_name)); var element_type = array_type.element_type.copy(); element_type.value_owned = false; element_expr = get_cvalue_(transform_value(new GLibValue(element_type, element_expr, true), stmt.type_reference, stmt)); visit_local_variable(stmt.element_variable); ccode.add_assignment(get_variable_cexpression(get_local_cname(stmt.element_variable)), element_expr); // set array length for stacked arrays if (stmt.type_reference is ArrayType) { var inner_array_type = (ArrayType)stmt.type_reference; for (int dim = 1; dim <= inner_array_type.rank; dim++) { ccode.add_assignment(get_variable_cexpression(get_array_length_cname(get_local_cname(stmt.element_variable), dim)), new CCodeConstant("-1")); } } stmt.body.emit(this); ccode.close(); } else if (stmt.collection.value_type.compatible(new ObjectType(glist_type)) || stmt.collection.value_type.compatible(new ObjectType(gslist_type))) { // iterating over a GList or GSList var iterator_variable = new LocalVariable(collection_type.copy(), stmt.variable_name + "_it"); visit_local_variable(iterator_variable); var it_name = get_local_cname(iterator_variable); var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.INEQUALITY, get_variable_cexpression(it_name), new CCodeConstant("NULL")); ccode.open_for(new CCodeAssignment(get_variable_cexpression(it_name), get_variable_cexpression(get_local_cname(collection_backup))), ccond, new CCodeAssignment(get_variable_cexpression(it_name), CCodeMemberAccess.pointer(get_variable_cexpression(it_name), "next"))); CCodeExpression element_expr = CCodeMemberAccess.pointer(get_variable_cexpression(it_name), "data"); if (collection_type.get_type_arguments().Count != 1) { Report.error(stmt.source_reference, "internal error: missing generic type argument"); stmt.error = true; return; } var element_data_type = collection_type.get_type_arguments()[0].copy(); element_data_type.value_owned = false; element_expr = convert_from_generic_pointer(element_expr, element_data_type); element_expr = get_cvalue_(transform_value(new GLibValue(element_data_type, element_expr), stmt.type_reference, stmt)); visit_local_variable(stmt.element_variable); ccode.add_assignment(get_variable_cexpression(get_local_cname(stmt.element_variable)), element_expr); stmt.body.emit(this); ccode.close(); } else if (stmt.collection.value_type.compatible(new ObjectType(gvaluearray_type))) { // iterating over a GValueArray var iterator_variable = new LocalVariable(uint_type.copy(), "%s_index".printf(stmt.variable_name)); visit_local_variable(iterator_variable); var arr_index = get_variable_cname(get_local_cname(iterator_variable)); var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.LESS_THAN, get_variable_cexpression(arr_index), CCodeMemberAccess.pointer(get_variable_cexpression(get_local_cname(collection_backup)), "n_values")); ccode.open_for(new CCodeAssignment(get_variable_cexpression(arr_index), new CCodeConstant("0")), ccond, new CCodeAssignment(get_variable_cexpression(arr_index), new CCodeBinaryExpression(CCodeBinaryOperator.PLUS, get_variable_cexpression(arr_index), new CCodeConstant("1")))); var get_item = new CCodeFunctionCall(new CCodeIdentifier("g_value_array_get_nth")); get_item.add_argument(get_variable_cexpression(get_local_cname(collection_backup))); get_item.add_argument(get_variable_cexpression(arr_index)); CCodeExpression element_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, get_item); if (stmt.type_reference.value_owned) { element_expr = get_cvalue_(copy_value(new GLibValue(stmt.type_reference, element_expr), new StructValueType(gvalue_type))); } visit_local_variable(stmt.element_variable); ccode.add_assignment(get_variable_cexpression(get_local_cname(stmt.element_variable)), element_expr); stmt.body.emit(this); ccode.close(); } foreach (LocalVariable local in stmt.get_local_variables()) { if (requires_destroy(local.variable_type)) { ccode.add_expression(destroy_local(local)); } } ccode.close(); }
void generate_async_function(Method m) { push_context(new EmitContext()); string callback_wrapper = null; if (!context.require_glib_version(2, 44)) { callback_wrapper = get_ccode_real_name(m) + "_async_ready_wrapper"; generate_async_ready_callback_wrapper(m, callback_wrapper); } var dataname = Symbol.lower_case_to_camel_case(get_ccode_name(m)) + "Data"; var asyncfunc = new CCodeFunction(get_ccode_real_name(m), "void"); var cparam_map = new Dictionary <int, CCodeParameter>(); cparam_map[get_param_pos(-1)] = new CCodeParameter("_callback_", "GAsyncReadyCallback"); cparam_map[get_param_pos(-0.9)] = new CCodeParameter("_user_data_", "gpointer"); generate_cparameters(m, cfile, cparam_map, asyncfunc, null, null, null, 1); if (m.base_method != null || m.base_interface_method != null) { // declare *_real_* function asyncfunc.modifiers |= CCodeModifiers.STATIC; cfile.add_function_declaration(asyncfunc); } else if (m.is_private_symbol()) { asyncfunc.modifiers |= CCodeModifiers.STATIC; } else if (context.hide_internal && m.is_internal_symbol()) { asyncfunc.modifiers |= CCodeModifiers.INTERNAL; } push_function(asyncfunc); // logic copied from valaccodemethodmodule if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) { Method base_method; if (m.overrides) { base_method = m.base_method; } else { base_method = m.base_interface_method; } var base_expression_type = new ObjectType((ObjectTypeSymbol)base_method.parent_symbol); var type_symbol = m.parent_symbol as ObjectTypeSymbol; var self_target_type = new ObjectType(type_symbol); var cself = get_cvalue_(transform_value(new GLibValue(base_expression_type, new CCodeIdentifier("base"), true), self_target_type, m)); ccode.add_declaration("%s *".printf(get_ccode_name(type_symbol)), new CCodeVariableDeclarator("self")); ccode.add_assignment(new CCodeIdentifier("self"), cself); } var dataalloc = new CCodeFunctionCall(new CCodeIdentifier("g_slice_new0")); dataalloc.add_argument(new CCodeIdentifier(dataname)); var data_var = new CCodeIdentifier("_data_"); ccode.add_declaration(dataname + "*", new CCodeVariableDeclarator("_data_")); ccode.add_assignment(data_var, dataalloc); if (!context.require_glib_version(2, 44)) { ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "_callback_"), new CCodeConstant("_callback_")); } var create_result = new CCodeFunctionCall(new CCodeIdentifier("g_task_new")); var t = m.parent_symbol as TypeSymbol; if (!(m is CreationMethod) && m.binding == MemberBinding.INSTANCE && t != null && t.is_subtype_of(gobject_type)) { var gobject_cast = new CCodeFunctionCall(new CCodeIdentifier("G_OBJECT")); gobject_cast.add_argument(new CCodeIdentifier("self")); create_result.add_argument(gobject_cast); } else { create_result.add_argument(new CCodeConstant("NULL")); } Parameter cancellable_param = null; foreach (Parameter param in m.get_parameters()) { if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name() == "GLib.Cancellable") { cancellable_param = param; break; } } if (cancellable_param == null) { create_result.add_argument(new CCodeConstant("NULL")); } else { create_result.add_argument(new CCodeIdentifier(get_variable_cname(cancellable_param.name))); } if (context.require_glib_version(2, 44)) { create_result.add_argument(new CCodeIdentifier("_callback_")); } else { create_result.add_argument(new CCodeIdentifier(callback_wrapper)); } create_result.add_argument(new CCodeIdentifier("_user_data_")); ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "_async_result"), create_result); if (!context.require_glib_version(2, 44)) { var task_completed_var = CCodeMemberAccess.pointer(data_var, "_task_complete_"); var callback = new CCodeIdentifier("_callback_"); var callback_is_null = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, callback, new CCodeConstant("NULL")); ccode.open_if(callback_is_null); ccode.add_assignment(task_completed_var, new CCodeConstant("TRUE")); ccode.close(); } var attach_data_call = new CCodeFunctionCall(new CCodeIdentifier("g_task_set_task_data")); attach_data_call.add_argument(CCodeMemberAccess.pointer(data_var, "_async_result")); attach_data_call.add_argument(data_var); attach_data_call.add_argument(new CCodeIdentifier(get_ccode_real_name(m) + "_data_free")); ccode.add_expression(attach_data_call); if (m is CreationMethod) { ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "object_type"), new CCodeIdentifier("object_type")); } else if (m.binding == MemberBinding.INSTANCE) { var this_type = m.this_parameter.variable_type.copy(); this_type.value_owned = true; // create copy if necessary as variables in async methods may need to be kept alive CCodeExpression cself = new CCodeIdentifier("self"); if (this_type.is_real_non_null_struct_type()) { cself = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, cself); } if (requires_copy(this_type)) { cself = get_cvalue_(copy_value(new GLibValue(m.this_parameter.variable_type, cself, true), m.this_parameter)); } ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "self"), cself); } emit_context.push_symbol(m); foreach (Parameter param in m.get_parameters()) { if (param.direction != ParameterDirection.OUT) { // create copy if necessary as variables in async methods may need to be kept alive var old_captured = param.captured; param.captured = false; current_method.coroutine = false; TargetValue value; if (param.variable_type.value_owned) { // do not use load_parameter for reference/ownership transfer // otherwise delegate destroy notify will not be moved value = get_parameter_cvalue(param); } else { value = load_parameter(param); } current_method.coroutine = true; store_parameter(param, value); param.captured = old_captured; } } emit_context.pop_symbol(); foreach (var type_param in m.get_type_parameters()) { var type = "%s_type".printf(type_param.name.ToLower()); var dup_func = "%s_dup_func".printf(type_param.name.ToLower()); var destroy_func = "%s_destroy_func".printf(type_param.name.ToLower()); ccode.add_assignment(CCodeMemberAccess.pointer(data_var, type), new CCodeIdentifier(type)); ccode.add_assignment(CCodeMemberAccess.pointer(data_var, dup_func), new CCodeIdentifier(dup_func)); ccode.add_assignment(CCodeMemberAccess.pointer(data_var, destroy_func), new CCodeIdentifier(destroy_func)); } var ccall = new CCodeFunctionCall(new CCodeIdentifier(get_ccode_real_name(m) + "_co")); ccall.add_argument(data_var); ccode.add_expression(ccall); cfile.add_function(asyncfunc); pop_context(); }
/* Returns access values to the given parameter */ public override TargetValue get_parameter_cvalue(Parameter param) { var result = new GLibValue(param.variable_type.copy()); result.lvalue = true; result.array_null_terminated = get_ccode_array_null_terminated(param); if (get_ccode_array_length_expr(param) != null) { result.array_length_cexpr = new CCodeConstant(get_ccode_array_length_expr(param)); } result.ctype = get_ccode_type(param); var array_type = result.value_type as ArrayType; var delegate_type = result.value_type as DelegateType; bool is_unowned_delegate = delegate_type != null && !param.variable_type.value_owned; if ((param.captured || is_in_coroutine()) && !is_unowned_delegate) { result.value_type.value_owned = true; } if (param.name == "this") { if (is_in_coroutine()) { // use closure result.cvalue = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), "self"); } else { var st = result.value_type.data_type as Struct; if (st != null && !st.is_simple_type()) { result.cvalue = new CCodeIdentifier("(*self)"); } else { result.cvalue = new CCodeIdentifier("self"); } } } else { string name = param.name; if (param.captured) { // captured variables are stored on the heap var block = param.parent_symbol as Block; if (block == null) { block = ((Method)param.parent_symbol).body; } result.cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_variable_cname(param.name)); if (array_type != null && get_ccode_array_length(param)) { for (int dim = 1; dim <= array_type.rank; dim++) { result.append_array_length_cvalue(CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_parameter_array_length_cname(param, dim))); } } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) { result.delegate_target_cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_ccode_delegate_target_name(param)); if (result.value_type.is_disposable()) { result.delegate_target_destroy_notify_cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_delegate_target_destroy_notify_cname(get_variable_cname(param.name))); } } } else if (is_in_coroutine()) { // use closure result.cvalue = get_variable_cexpression(param.name); if (delegate_type != null && delegate_type.delegate_symbol.has_target) { result.delegate_target_cvalue = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), get_ccode_delegate_target_name(param)); if (delegate_type.is_disposable()) { result.delegate_target_destroy_notify_cvalue = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), get_delegate_target_destroy_notify_cname(get_variable_cname(param.name))); } } } else { var type_as_struct = result.value_type.data_type as Struct; if (param.direction == ParameterDirection.OUT) { name = "_vala_%s".printf(name); } if (param.direction == ParameterDirection.REF || (param.direction == ParameterDirection.IN && type_as_struct != null && !type_as_struct.is_simple_type() && !result.value_type.nullable)) { result.cvalue = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier(get_variable_cname(name))); } else { // Property setters of non simple structs shall replace all occurrences // of the "value" formal parameter with a dereferencing version of that // parameter. if (current_property_accessor != null && current_property_accessor.writable && current_property_accessor.value_parameter == param && current_property_accessor.prop.property_type.is_real_struct_type() && !current_property_accessor.prop.property_type.nullable) { result.cvalue = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("value")); } else { result.cvalue = get_variable_cexpression(name); } } if (delegate_type != null && delegate_type.delegate_symbol.has_target) { var target_cname = get_ccode_delegate_target_name(param); if (param.direction == ParameterDirection.OUT) { target_cname = "_vala_%s".printf(target_cname); } CCodeExpression target_expr = new CCodeIdentifier(target_cname); CCodeExpression delegate_target_destroy_notify = new CCodeIdentifier(get_delegate_target_destroy_notify_cname(get_variable_cname(name))); if (param.direction == ParameterDirection.REF) { // accessing argument of ref param target_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, target_expr); delegate_target_destroy_notify = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify); } result.delegate_target_cvalue = target_expr; if (result.value_type.is_disposable()) { result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify; } } } if (!param.captured && array_type != null) { if (get_ccode_array_length(param) && !get_ccode_array_null_terminated(param)) { for (int dim = 1; dim <= array_type.rank; dim++) { CCodeExpression length_expr = get_variable_cexpression(get_parameter_array_length_cname(param, dim)); if (param.direction == ParameterDirection.OUT) { length_expr = get_variable_cexpression(get_array_length_cname(get_variable_cname(name), dim)); } else if (param.direction == ParameterDirection.REF) { // accessing argument of ref param length_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, length_expr); } result.append_array_length_cvalue(length_expr); } } } } return(result); }
/* Returns lvalue access to the given local variable */ public override TargetValue get_local_cvalue(LocalVariable local) { var result = new GLibValue(local.variable_type.copy()); result.lvalue = true; var array_type = local.variable_type as ArrayType; var delegate_type = local.variable_type as DelegateType; if (local.is_result) { // used in postconditions // structs are returned as out parameter if (local.variable_type != null && local.variable_type.is_real_non_null_struct_type()) { result.cvalue = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("result")); } else { result.cvalue = new CCodeIdentifier("result"); } if (array_type != null && !array_type.fixed_length && ((current_method != null && get_ccode_array_length(current_method)) || current_property_accessor != null)) { for (int dim = 1; dim <= array_type.rank; dim++) { result.append_array_length_cvalue(new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression(get_array_length_cname("result", dim)))); } } } else if (local.captured) { // captured variables are stored on the heap var block = (Block)local.parent_symbol; result.cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_local_cname(local)); if (array_type != null && !array_type.fixed_length) { for (int dim = 1; dim <= array_type.rank; dim++) { result.append_array_length_cvalue(CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_array_length_cname(get_local_cname(local), dim))); } if (array_type.rank == 1) { result.array_size_cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_array_size_cname(get_local_cname(local))); } } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) { result.delegate_target_cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_delegate_target_cname(get_local_cname(local))); if (delegate_type.is_disposable()) { result.delegate_target_destroy_notify_cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_delegate_target_destroy_notify_cname(get_local_cname(local))); } } } else { result.cvalue = get_local_cexpression(local); if (array_type != null && !array_type.fixed_length) { for (int dim = 1; dim <= array_type.rank; dim++) { result.append_array_length_cvalue(get_variable_cexpression(get_array_length_cname(get_local_cname(local), dim))); } if (array_type.rank == 1) { result.array_size_cvalue = get_variable_cexpression(get_array_size_cname(get_local_cname(local))); } } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) { if (is_in_coroutine()) { result.delegate_target_cvalue = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), get_delegate_target_cname(get_local_cname(local))); if (local.variable_type.value_owned) { result.delegate_target_destroy_notify_cvalue = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), get_delegate_target_destroy_notify_cname(get_local_cname(local))); } } else { result.delegate_target_cvalue = new CCodeIdentifier(get_delegate_target_cname(get_local_cname(local))); if (local.variable_type.value_owned) { result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier(get_delegate_target_destroy_notify_cname(get_local_cname(local))); } } } } return(result); }
public override void visit_member_access(MemberAccess expr) { CCodeExpression pub_inst = null; if (expr.inner != null) { pub_inst = get_cvalue(expr.inner); } var array_type = expr.value_type as ArrayType; var delegate_type = expr.value_type as DelegateType; if (expr.symbol_reference is Method) { var m = (Method)expr.symbol_reference; if (!(m is DynamicMethod || m is ArrayMoveMethod || m is ArrayResizeMethod || m is ArrayCopyMethod)) { generate_method_declaration(m, cfile); if (!m.external && m.external_package) { // internal VAPI methods // only add them once per source file if (add_generated_external_symbol(m)) { visit_method(m); } } } if (expr.inner is BaseAccess) { if (m.base_method != null) { var base_class = (Class)m.base_method.parent_symbol; var vcast = new CCodeFunctionCall(new CCodeIdentifier("%s_CLASS".printf(get_ccode_upper_case_name(base_class, null)))); vcast.add_argument(new CCodeIdentifier("%s_parent_class".printf(get_ccode_lower_case_name(current_class, null)))); set_cvalue(expr, CCodeMemberAccess.pointer(vcast, get_ccode_vfunc_name(m))); return; } else if (m.base_interface_method != null) { var base_iface = (Interface)m.base_interface_method.parent_symbol; string parent_iface_var = "%s_%s_parent_iface".printf(get_ccode_lower_case_name(current_class), get_ccode_lower_case_name(base_iface)); set_cvalue(expr, CCodeMemberAccess.pointer(new CCodeIdentifier(parent_iface_var), get_ccode_vfunc_name(m))); return; } } if (m.base_method != null) { if (!method_has_wrapper(m.base_method)) { var base_class = (Class)m.base_method.parent_symbol; var vclass = new CCodeFunctionCall(new CCodeIdentifier("%s_GET_CLASS".printf(get_ccode_upper_case_name(base_class)))); vclass.add_argument(pub_inst); set_cvalue(expr, CCodeMemberAccess.pointer(vclass, get_ccode_vfunc_name(m))); } else { set_cvalue(expr, new CCodeIdentifier(get_ccode_name(m.base_method))); } } else if (m.base_interface_method != null) { set_cvalue(expr, new CCodeIdentifier(get_ccode_name(m.base_interface_method))); } else if (m is CreationMethod) { set_cvalue(expr, new CCodeIdentifier(get_ccode_real_name(m))); } else { set_cvalue(expr, new CCodeIdentifier(get_ccode_name(m))); } set_delegate_target_destroy_notify(expr, new CCodeConstant("NULL")); if (m.binding == MemberBinding.STATIC) { set_delegate_target(expr, new CCodeConstant("NULL")); } else if (m.is_async_callback) { if (current_method.closure) { var block = ((Method)m.parent_symbol).body; set_delegate_target(expr, CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), "_async_data_")); } else { set_delegate_target(expr, new CCodeIdentifier("_data_")); } } else if (expr.inner != null && !expr.prototype_access) { // expr.inner is null in the special case of referencing the method in a constant initializer var delegate_target = (CCodeExpression)get_ccodenode(expr.inner); delegate_type = expr.target_type as DelegateType; if ((expr.value_type.value_owned || (delegate_type != null && delegate_type.is_called_once)) && expr.inner.value_type.data_type != null && is_reference_counting(expr.inner.value_type.data_type)) { var ref_call = new CCodeFunctionCall(get_dup_func_expression(expr.inner.value_type, expr.source_reference)); ref_call.add_argument(delegate_target); delegate_target = ref_call; set_delegate_target_destroy_notify(expr, get_destroy_func_expression(expr.inner.value_type)); } set_delegate_target(expr, delegate_target); } } else if (expr.symbol_reference is ArrayLengthField) { if (expr.value_type is ArrayType && !(expr.parent_node is ElementAccess)) { Report.error(expr.source_reference, "unsupported use of length field of multi-dimensional array"); } set_cvalue(expr, get_array_length_cexpression(expr.inner, 1)); } else if (expr.symbol_reference is Field) { var field = (Field)expr.symbol_reference; if (expr.lvalue) { expr.target_value = get_field_cvalue(field, expr.inner != null ? expr.inner.target_value : null); } else { expr.target_value = load_field(field, expr.inner != null ? expr.inner.target_value : null); } } else if (expr.symbol_reference is EnumValue) { var ev = (EnumValue)expr.symbol_reference; generate_enum_declaration((ValaEnum)ev.parent_symbol, cfile); set_cvalue(expr, new CCodeConstant(get_ccode_name(ev))); } else if (expr.symbol_reference is Constant) { var c = (Constant)expr.symbol_reference; generate_constant_declaration(c, cfile, c.source_reference != null && expr.source_reference != null && c.source_reference.file == expr.source_reference.file); string fn = c.get_full_name(); if (fn == "GLib.Log.FILE") { string s = Path.GetFileName(expr.source_reference.file.filename); set_cvalue(expr, new CCodeConstant("\"%s\"".printf(s))); } else if (fn == "GLib.Log.LINE") { int i = expr.source_reference.begin.line; set_cvalue(expr, new CCodeConstant("%d".printf(i))); } else if (fn == "GLib.Log.METHOD") { string s = ""; if (current_method != null) { s = current_method.get_full_name(); } set_cvalue(expr, new CCodeConstant("\"%s\"".printf(s))); } else { set_cvalue(expr, new CCodeIdentifier(get_ccode_name(c))); } if (array_type != null) { var ccall = new CCodeFunctionCall(new CCodeIdentifier("G_N_ELEMENTS")); ccall.add_argument(new CCodeIdentifier(get_ccode_name(c))); append_array_length(expr, ccall); } } else if (expr.symbol_reference is Property) { var prop = (Property)expr.symbol_reference; if (!(prop is DynamicProperty)) { generate_property_accessor_declaration(prop.get_accessor, cfile); if (!prop.external && prop.external_package) { // internal VAPI properties // only add them once per source file if (add_generated_external_symbol(prop)) { visit_property(prop); } } } if (expr.inner is BaseAccess) { var base_prop = prop; if (prop.base_property != null) { base_prop = prop.base_property; } else if (prop.base_interface_property != null) { base_prop = prop.base_interface_property; } if (base_prop.parent_symbol is Class) { var base_class = (Class)base_prop.parent_symbol; var vcast = new CCodeFunctionCall(new CCodeIdentifier("%s_CLASS".printf(get_ccode_upper_case_name(base_class, null)))); vcast.add_argument(new CCodeIdentifier("%s_parent_class".printf(get_ccode_lower_case_name(current_class, null)))); var ccall = new CCodeFunctionCall(CCodeMemberAccess.pointer(vcast, "get_%s".printf(prop.name))); ccall.add_argument(get_cvalue(expr.inner)); if (prop.property_type.is_real_non_null_struct_type()) { var temp_value = (GLibValue)create_temp_value(prop.get_accessor.value_type, false, expr); expr.target_value = load_temp_value(temp_value); var ctemp = get_cvalue_(temp_value); ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, ctemp)); ccode.add_expression(ccall); } else { set_cvalue(expr, ccall); } } else if (base_prop.parent_symbol is Interface) { var base_iface = (Interface)base_prop.parent_symbol; string parent_iface_var = "%s_%s_parent_iface".printf(get_ccode_lower_case_name(current_class), get_ccode_lower_case_name(base_iface)); var ccall = new CCodeFunctionCall(CCodeMemberAccess.pointer(new CCodeIdentifier(parent_iface_var), "get_%s".printf(prop.name))); ccall.add_argument(get_cvalue(expr.inner)); if (prop.property_type.is_real_non_null_struct_type()) { var temp_value = (GLibValue)create_temp_value(prop.get_accessor.value_type, false, expr); expr.target_value = load_temp_value(temp_value); var ctemp = get_cvalue_(temp_value); ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, ctemp)); ccode.add_expression(ccall); } else { set_cvalue(expr, ccall); } } } else if (prop.binding == MemberBinding.INSTANCE && prop.get_accessor.automatic_body && !prop.get_accessor.value_type.value_owned && current_type_symbol == prop.parent_symbol && current_type_symbol is Class && prop.base_property == null && prop.base_interface_property == null && !(prop.property_type is ArrayType || prop.property_type is DelegateType)) { CCodeExpression inst; inst = CCodeMemberAccess.pointer(pub_inst, "priv"); set_cvalue(expr, CCodeMemberAccess.pointer(inst, get_ccode_name(prop.field))); } else if (!get_ccode_no_accessor_method(prop)) { string getter_cname; if (prop is DynamicProperty) { getter_cname = get_dynamic_property_getter_cname((DynamicProperty)prop); } else { getter_cname = get_ccode_name(prop.get_accessor); } var ccall = new CCodeFunctionCall(new CCodeIdentifier(getter_cname)); if (prop.binding == MemberBinding.INSTANCE) { if (prop.parent_symbol is Struct && !((Struct)prop.parent_symbol).is_simple_type()) { // we need to pass struct instance by reference var instance = expr.inner.target_value; if (!get_lvalue(instance)) { instance = store_temp_value(instance, expr); } pub_inst = new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, get_cvalue_(instance)); } ccall.add_argument(pub_inst); } bool prop_is_real_non_null_struct_type = prop.property_type.is_real_non_null_struct_type(); var temp_value = (GLibValue)create_temp_value(prop.get_accessor.value_type, prop_is_real_non_null_struct_type, expr); expr.target_value = load_temp_value(temp_value); var ctemp = get_cvalue_(temp_value); // Property access to real struct types is handled differently // The value is returned by out parameter if (prop_is_real_non_null_struct_type) { ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, ctemp)); ccode.add_expression(ccall); } else { ccode.add_assignment(ctemp, ccall); array_type = prop.property_type as ArrayType; if (array_type != null) { if (get_ccode_array_null_terminated(prop)) { requires_array_length = true; var len_call = new CCodeFunctionCall(new CCodeIdentifier("_vala_array_length")); len_call.add_argument(ctemp); ccode.add_assignment(temp_value.array_length_cvalues[0], len_call); } else if (get_ccode_array_length(prop)) { for (int dim = 1; dim <= array_type.rank; dim++) { ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue(temp_value, dim))); } } } else { delegate_type = prop.property_type as DelegateType; if (delegate_type != null && delegate_type.delegate_symbol.has_target) { ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_cvalue(temp_value))); } } } } else { var ccall = new CCodeFunctionCall(new CCodeIdentifier("g_object_get")); ccall.add_argument(pub_inst); // property name is second argument of g_object_get ccall.add_argument(get_property_canonical_cconstant(prop)); // g_object_get always returns owned values // therefore, property getters of properties // without accessor methods need to be marked as owned if (!prop.get_accessor.value_type.value_owned) { // only report error for types where there actually // is a difference between `owned' and `unowned' var owned_value_type = prop.get_accessor.value_type.copy(); owned_value_type.value_owned = true; if (requires_copy(owned_value_type)) { Report.error(prop.get_accessor.source_reference, "unowned return value for getter of property `%s' not supported without accessor".printf(prop.get_full_name())); } } if (expr.value_type.is_real_struct_type()) { // gobject allocates structs on heap expr.value_type.nullable = true; } var temp_var = get_temp_variable(expr.value_type); var ctemp = get_variable_cexpression(temp_var.name); emit_temp_var(temp_var); ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, ctemp)); ccall.add_argument(new CCodeConstant("NULL")); ccode.add_expression(ccall); set_cvalue(expr, ctemp); } expr.target_value.value_type = expr.value_type; expr.target_value = store_temp_value(expr.target_value, expr); } else if (expr.symbol_reference is LocalVariable) { var local = (LocalVariable)expr.symbol_reference; if (expr.parent_node is ReturnStatement && current_return_type.value_owned && local.variable_type.value_owned && !local.captured && !variable_accessible_in_finally(local) && !(local.variable_type is ArrayType && ((ArrayType)local.variable_type).inline_allocated)) { /* return expression is local variable taking ownership and * current method is transferring ownership */ // don't ref expression expr.value_type.value_owned = true; // don't unref variable local.active = false; var glib_value = (GLibValue)get_local_cvalue(local); expr.target_value = glib_value; if (glib_value.delegate_target_cvalue == null) { glib_value.delegate_target_cvalue = new CCodeConstant("NULL"); } if (glib_value.delegate_target_destroy_notify_cvalue == null) { glib_value.delegate_target_destroy_notify_cvalue = new CCodeConstant("NULL"); } } else { if (expr.lvalue) { expr.target_value = get_local_cvalue(local); } else { expr.target_value = load_local(local); } } } else if (expr.symbol_reference is Parameter) { var param = (Parameter)expr.symbol_reference; if (expr.lvalue) { expr.target_value = get_parameter_cvalue(param); } else { expr.target_value = load_parameter(param); } } }
void generate_finish_function(Method m) { push_context(new EmitContext()); string dataname = Symbol.lower_case_to_camel_case(get_ccode_name(m)) + "Data"; var finishfunc = new CCodeFunction(get_ccode_finish_real_name(m)); var cparam_map = new Dictionary <int, CCodeParameter>(); cparam_map[get_param_pos(0.1)] = new CCodeParameter("_res_", "GAsyncResult*"); generate_cparameters(m, cfile, cparam_map, finishfunc, null, null, null, 2); if (m.is_private_symbol() || m.base_method != null || m.base_interface_method != null) { finishfunc.modifiers |= CCodeModifiers.STATIC; } else if (context.hide_internal && m.is_internal_symbol()) { finishfunc.modifiers |= CCodeModifiers.INTERNAL; } push_function(finishfunc); var return_type = m.return_type; if (m is CreationMethod) { var type_sym = (TypeSymbol)m.parent_symbol; if (type_sym is ObjectTypeSymbol) { ccode.add_declaration(get_ccode_name(type_sym) + "*", new CCodeVariableDeclarator("result")); } } else if (!(return_type is VoidType) && !return_type.is_real_non_null_struct_type()) { ccode.add_declaration(get_ccode_name(m.return_type), new CCodeVariableDeclarator("result")); } var data_var = new CCodeIdentifier("_data_"); ccode.add_declaration(dataname + "*", new CCodeVariableDeclarator("_data_")); var async_result_cast = new CCodeFunctionCall(new CCodeIdentifier("G_TASK")); async_result_cast.add_argument(new CCodeIdentifier("_res_")); var ccall = new CCodeFunctionCall(new CCodeIdentifier("g_task_propagate_pointer")); ccall.add_argument(async_result_cast); if (m.get_error_types().Count > 0) { ccall.add_argument(new CCodeIdentifier("error")); } else { ccall.add_argument(new CCodeConstant("NULL")); } ccode.add_assignment(data_var, ccall); bool has_cancellable = false; foreach (Parameter param in m.get_parameters()) { if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name() == "GLib.Cancellable") { has_cancellable = true; break; } } // If a task is cancelled, g_task_propagate_pointer returns NULL if (m.get_error_types().Count > 0 || has_cancellable) { var is_null = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, new CCodeConstant("NULL"), data_var); ccode.open_if(is_null); return_default_value(return_type); ccode.close(); } emit_context.push_symbol(m); foreach (Parameter param in m.get_parameters()) { if (param.direction != ParameterDirection.IN) { return_out_parameter(param); if (!(param.variable_type is ValaValueType) || param.variable_type.nullable) { ccode.add_assignment(CCodeMemberAccess.pointer(data_var, get_variable_cname(param.name)), new CCodeConstant("NULL")); } } } emit_context.pop_symbol(); if (m is CreationMethod) { ccode.add_assignment(new CCodeIdentifier("result"), CCodeMemberAccess.pointer(data_var, "self")); ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "self"), new CCodeConstant("NULL")); ccode.add_return(new CCodeIdentifier("result")); } else if (return_type.is_real_non_null_struct_type()) { // structs are returned via out parameter CCodeExpression cexpr = CCodeMemberAccess.pointer(data_var, "result"); if (requires_copy(return_type)) { cexpr = get_cvalue_(copy_value(new GLibValue(return_type, cexpr, true), return_type)); } ccode.add_assignment(new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("result")), cexpr); } else if (!(return_type is VoidType)) { ccode.add_assignment(new CCodeIdentifier("result"), CCodeMemberAccess.pointer(data_var, "result")); if (return_type is ArrayType) { var array_type = (ArrayType)return_type; if (get_ccode_array_length(m)) { for (int dim = 1; dim <= array_type.rank; dim++) { ccode.add_assignment(new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier(get_array_length_cname("result", dim))), CCodeMemberAccess.pointer(data_var, get_array_length_cname("result", dim))); } } } else if (return_type is DelegateType && ((DelegateType)return_type).delegate_symbol.has_target) { ccode.add_assignment(new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier(get_delegate_target_cname("result"))), CCodeMemberAccess.pointer(data_var, get_delegate_target_cname("result"))); } if (!(return_type is ValaValueType) || return_type.nullable) { ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "result"), new CCodeConstant("NULL")); } ccode.add_return(new CCodeIdentifier("result")); } pop_function(); cfile.add_function(finishfunc); pop_context(); }
public override void add_simple_check(CodeNode node, bool always_fails = false) { current_method_inner_error = true; var inner_error = get_variable_cexpression("_inner_error_"); if (always_fails) { // inner_error is always set, avoid unnecessary if statement // eliminates C warnings } else { var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.INEQUALITY, inner_error, new CCodeConstant("NULL")); var unlikely = new CCodeFunctionCall(new CCodeIdentifier("G_UNLIKELY")); unlikely.add_argument(ccond); ccode.open_if(unlikely); } if (current_try != null) { // surrounding try found // free local variables if (is_in_catch) { append_local_free(current_symbol, false, current_catch); } else { append_local_free(current_symbol, false, current_try); } var error_types = new List <DataType>(); foreach (DataType node_error_type in node.get_error_types()) { error_types.Add(node_error_type); } bool has_general_catch_clause = false; if (!is_in_catch) { var handled_error_types = new List <DataType>(); foreach (CatchClause clause in current_try.get_catch_clauses()) { // keep track of unhandled error types foreach (DataType node_error_type in error_types) { if (clause.error_type == null || node_error_type.compatible(clause.error_type)) { handled_error_types.Add(node_error_type); } } foreach (DataType handled_error_type in handled_error_types) { error_types.Remove(handled_error_type); } handled_error_types.Clear(); if (clause.error_type.equals(gerror_type)) { // general catch clause, this should be the last one has_general_catch_clause = true; ccode.add_goto(clause.clabel_name); break; } else { var catch_type = clause.error_type as ErrorType; if (catch_type.error_code != null) { /* catch clause specifies a specific error code */ var error_match = new CCodeFunctionCall(new CCodeIdentifier("g_error_matches")); error_match.add_argument(inner_error); error_match.add_argument(new CCodeIdentifier(get_ccode_upper_case_name(catch_type.data_type))); error_match.add_argument(new CCodeIdentifier(get_ccode_name(catch_type.error_code))); ccode.open_if(error_match); } else { /* catch clause specifies a full error domain */ var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, CCodeMemberAccess.pointer(inner_error, "domain"), new CCodeIdentifier (get_ccode_upper_case_name(clause.error_type.data_type))); ccode.open_if(ccond); } // go to catch clause if error domain matches ccode.add_goto(clause.clabel_name); ccode.close(); } } } if (has_general_catch_clause) { // every possible error is already caught // as there is a general catch clause // no need to do anything else } else if (error_types.Count > 0) { // go to finally clause if no catch clause matches // and there are still unhandled error types ccode.add_goto("__finally%d".printf(current_try_id)); } else if (in_finally_block(node)) { // do not check unexpected errors happening within finally blocks // as jump out of finally block is not supported } else { // should never happen with correct bindings uncaught_error_statement(inner_error, true); } } else if (current_method != null && current_method.get_error_types().Count > 0) { // current method can fail, propagate error CCodeBinaryExpression ccond = null; foreach (DataType error_type in current_method.get_error_types()) { // If GLib.Error is allowed we propagate everything if (error_type.equals(gerror_type)) { ccond = null; break; } // Check the allowed error domains to propagate var domain_check = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, CCodeMemberAccess.pointer (inner_error, "domain"), new CCodeIdentifier(get_ccode_upper_case_name(error_type.data_type))); if (ccond == null) { ccond = domain_check; } else { ccond = new CCodeBinaryExpression(CCodeBinaryOperator.OR, ccond, domain_check); } } if (ccond != null) { ccode.open_if(ccond); return_with_exception(inner_error); ccode.add_else(); uncaught_error_statement(inner_error); ccode.close(); } else { return_with_exception(inner_error); } } else { uncaught_error_statement(inner_error); } if (!always_fails) { ccode.close(); } }
/* Returns lvalue access to the given field */ public override TargetValue get_field_cvalue(Field field, TargetValue instance) { var value_type = field.variable_type.copy(); var result = new GLibValue(value_type); if (instance != null) { result.actual_value_type = field.variable_type.get_actual_type(instance.value_type, null, field); } result.lvalue = true; result.array_null_terminated = get_ccode_array_null_terminated(field); if (get_ccode_array_length_expr(field) != null) { result.array_length_cexpr = new CCodeConstant(get_ccode_array_length_expr(field)); } result.ctype = get_ccode_type(field); var array_type = result.value_type as ArrayType; var delegate_type = result.value_type as DelegateType; if (field.binding == MemberBinding.INSTANCE) { CCodeExpression pub_inst = null; if (instance != null) { pub_inst = get_cvalue_(instance); } var instance_target_type = get_data_type_for_symbol((TypeSymbol)field.parent_symbol); var cl = instance_target_type.data_type as Class; bool is_gtypeinstance = ((instance_target_type.data_type == cl) && (cl == null || !cl.is_compact)); CCodeExpression inst; if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) { inst = CCodeMemberAccess.pointer(pub_inst, "priv"); } else { if (cl != null) { generate_class_struct_declaration(cl, cfile); } inst = pub_inst; } if (instance_target_type.data_type.is_reference_type() || (instance != null && instance.value_type is PointerType)) { result.cvalue = CCodeMemberAccess.pointer(inst, get_ccode_name(field)); } else { result.cvalue = new CCodeMemberAccess(inst, get_ccode_name(field)); } if (array_type != null && get_ccode_array_length(field)) { for (int dim = 1; dim <= array_type.rank; dim++) { CCodeExpression length_expr = null; string length_cname; if (get_ccode_array_length_name(field) != null) { length_cname = get_ccode_array_length_name(field); } else { length_cname = get_array_length_cname(get_ccode_name(field), dim); } if (((TypeSymbol)field.parent_symbol).is_reference_type()) { length_expr = CCodeMemberAccess.pointer(inst, length_cname); } else { length_expr = new CCodeMemberAccess(inst, length_cname); } result.append_array_length_cvalue(length_expr); } if (array_type.rank == 1 && field.is_internal_symbol()) { string size_cname = get_array_size_cname(get_ccode_name(field)); if (((TypeSymbol)field.parent_symbol).is_reference_type()) { set_array_size_cvalue(result, CCodeMemberAccess.pointer(inst, size_cname)); } else { set_array_size_cvalue(result, new CCodeMemberAccess(inst, size_cname)); } } } else if (delegate_type != null && delegate_type.delegate_symbol.has_target && get_ccode_delegate_target(field)) { string target_cname = get_ccode_delegate_target_name(field); string target_destroy_notify_cname = get_delegate_target_destroy_notify_cname(get_ccode_name(field)); if (((TypeSymbol)field.parent_symbol).is_reference_type()) { result.delegate_target_cvalue = CCodeMemberAccess.pointer(inst, target_cname); if (result.value_type.is_disposable()) { result.delegate_target_destroy_notify_cvalue = CCodeMemberAccess.pointer(inst, target_destroy_notify_cname); } } else { result.delegate_target_cvalue = new CCodeMemberAccess(inst, target_cname); if (result.value_type.is_disposable()) { result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess(inst, target_destroy_notify_cname); } } } } else if (field.binding == MemberBinding.CLASS) { var cl = (Class)field.parent_symbol; var cast = new CCodeFunctionCall(new CCodeIdentifier(get_ccode_upper_case_name(cl, null) + "_CLASS")); CCodeExpression klass; if (instance == null) { if (get_this_type() == null) { // Accessing the field from a static or class constructor klass = new CCodeIdentifier("klass"); } else { // Accessing the field from within an instance method var k = new CCodeFunctionCall(new CCodeIdentifier("G_OBJECT_GET_CLASS")); k.add_argument(new CCodeIdentifier("self")); klass = k; } } else { // Accessing the field of an instance var k = new CCodeFunctionCall(new CCodeIdentifier("G_OBJECT_GET_CLASS")); k.add_argument(get_cvalue_(instance)); klass = k; } cast.add_argument(klass); if (field.access == SymbolAccessibility.PRIVATE) { var ccall = new CCodeFunctionCall(new CCodeIdentifier("%s_GET_CLASS_PRIVATE".printf(get_ccode_upper_case_name(cl)))); ccall.add_argument(klass); result.cvalue = CCodeMemberAccess.pointer(ccall, get_ccode_name(field)); } else { result.cvalue = CCodeMemberAccess.pointer(cast, get_ccode_name(field)); } } else { generate_field_declaration(field, cfile); result.cvalue = new CCodeIdentifier(get_ccode_name(field)); if (array_type != null && get_ccode_array_length(field)) { for (int dim = 1; dim <= array_type.rank; dim++) { string length_cname; if (get_ccode_array_length_name(field) != null) { length_cname = get_ccode_array_length_name(field); } else { length_cname = get_array_length_cname(get_ccode_name(field), dim); } result.append_array_length_cvalue(new CCodeIdentifier(length_cname)); } if (array_type.rank == 1 && field.is_internal_symbol()) { set_array_size_cvalue(result, new CCodeIdentifier(get_array_size_cname(get_ccode_name(field)))); } } else if (delegate_type != null && delegate_type.delegate_symbol.has_target && get_ccode_delegate_target(field)) { result.delegate_target_cvalue = new CCodeIdentifier(get_ccode_delegate_target_name(field)); if (result.value_type.is_disposable()) { result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier(get_delegate_target_destroy_notify_cname(get_ccode_name(field))); } } } return(result); }