CCodeExpression serialize_array_dim(ArrayType array_type, int dim, CCodeExpression array_expr, CCodeExpression array_iter_expr) { string builder_name = "_tmp%d_".printf(next_temp_var_id++); string index_name = "_tmp%d_".printf(next_temp_var_id++); ccode.add_declaration("GVariantBuilder", new CCodeVariableDeclarator(builder_name)); ccode.add_declaration("int", new CCodeVariableDeclarator(index_name)); var gvariant_type = new CCodeFunctionCall(new CCodeIdentifier("G_VARIANT_TYPE")); gvariant_type.add_argument(new CCodeConstant("\"%s\"".printf(get_type_signature(array_type)))); var builder_init = new CCodeFunctionCall(new CCodeIdentifier("g_variant_builder_init")); builder_init.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(builder_name))); builder_init.add_argument(gvariant_type); ccode.add_expression(builder_init); var cforinit = new CCodeAssignment(new CCodeIdentifier(index_name), new CCodeConstant("0")); var cforcond = new CCodeBinaryExpression(CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier(index_name), get_array_length(array_expr, dim)); var cforiter = new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier(index_name)); ccode.open_for(cforinit, cforcond, cforiter); CCodeExpression element_variant; if (dim < array_type.rank) { element_variant = serialize_array_dim(array_type, dim + 1, array_expr, array_iter_expr); } else { var element_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr); element_variant = serialize_expression(array_type.element_type, element_expr); } var builder_add = new CCodeFunctionCall(new CCodeIdentifier("g_variant_builder_add_value")); builder_add.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(builder_name))); builder_add.add_argument(element_variant); ccode.add_expression(builder_add); if (dim == array_type.rank) { var array_iter_incr = new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr); ccode.add_expression(array_iter_incr); } ccode.close(); var builder_end = new CCodeFunctionCall(new CCodeIdentifier("g_variant_builder_end")); builder_end.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(builder_name))); return(builder_end); }
public override CCodeExpression serialize_expression(DataType type, CCodeExpression expr) { BasicTypeInfo basic_type; CCodeExpression result = null; if (is_string_marshalled_enum(type.data_type)) { get_basic_type_info("s", out basic_type); result = generate_enum_value_to_string(type as EnumValueType, expr); result = serialize_basic(basic_type, result); } else if (get_basic_type_info(get_type_signature(type), out basic_type)) { result = serialize_basic(basic_type, expr); } else if (type is ArrayType) { result = serialize_array((ArrayType)type, expr); } else if (type.data_type is Struct) { var st_expr = expr; if (type.nullable) { st_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, st_expr); } result = serialize_struct((Struct)type.data_type, st_expr); } else if (type is ObjectType) { if (type.data_type.get_full_name() == "GLib.Variant") { var variant_new = new CCodeFunctionCall(new CCodeIdentifier("g_variant_new_variant")); variant_new.add_argument(expr); result = variant_new; } else if (type.data_type.get_full_name() == "GLib.HashTable") { result = serialize_hash_table((ObjectType)type, expr); } } if (result == null) { Report.error(type.source_reference, "GVariant serialization of type `%s' is not supported".printf(type.ToString())); } return(result); }
string generate_array_add_wrapper(ArrayType array_type) { string add_func = "_vala_array_add%d".printf(++next_array_add_id); if (!add_wrapper(add_func)) { // wrapper already defined return(add_func); } var function = new CCodeFunction(add_func, "void"); function.modifiers = CCodeModifiers.STATIC; function.add_parameter(new CCodeParameter("array", "%s *".printf(get_ccode_name(array_type)))); function.add_parameter(new CCodeParameter("length", "int*")); function.add_parameter(new CCodeParameter("size", "int*")); push_function(function); string typename = get_ccode_name(array_type.element_type); CCodeExpression value = new CCodeIdentifier("value"); if (array_type.element_type.is_real_struct_type()) { if (!array_type.element_type.nullable || !array_type.element_type.value_owned) { typename = "const " + typename; } if (!array_type.element_type.nullable) { typename += "*"; value = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, value); } } function.add_parameter(new CCodeParameter("value", typename)); var array = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("array")); var length = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("length")); var size = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("size")); var renew_call = new CCodeFunctionCall(new CCodeIdentifier("g_renew")); renew_call.add_argument(new CCodeIdentifier(get_ccode_name(array_type.element_type))); renew_call.add_argument(array); if (array_type.element_type.is_reference_type_or_type_parameter()) { // NULL terminate array renew_call.add_argument(new CCodeBinaryExpression(CCodeBinaryOperator.PLUS, size, new CCodeConstant("1"))); } else { renew_call.add_argument(size); } var csizecheck = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, length, size); ccode.open_if(csizecheck); ccode.add_assignment(size, new CCodeConditionalExpression(size, new CCodeBinaryExpression(CCodeBinaryOperator.MUL, new CCodeConstant("2"), size), new CCodeConstant("4"))); ccode.add_assignment(array, renew_call); ccode.close(); ccode.add_assignment(new CCodeElementAccess(array, new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value); if (array_type.element_type.is_reference_type_or_type_parameter()) { // NULL terminate array ccode.add_assignment(new CCodeElementAccess(array, length), new CCodeConstant("NULL")); } pop_function(); cfile.add_function_declaration(function); cfile.add_function(function); return(add_func); }
void deserialize_array_dim(ArrayType array_type, int dim, string temp_name, CCodeExpression variant_expr, CCodeExpression expr) { string subiter_name = "_tmp%d_".printf(next_temp_var_id++); string element_name = "_tmp%d_".printf(next_temp_var_id++); ccode.add_declaration("int", new CCodeVariableDeclarator("%s_length%d".printf(temp_name, dim), new CCodeConstant("0"))); ccode.add_declaration("GVariantIter", new CCodeVariableDeclarator(subiter_name)); ccode.add_declaration("GVariant*", new CCodeVariableDeclarator(element_name)); var iter_call = new CCodeFunctionCall(new CCodeIdentifier("g_variant_iter_init")); iter_call.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(subiter_name))); iter_call.add_argument(variant_expr); ccode.add_expression(iter_call); iter_call = new CCodeFunctionCall(new CCodeIdentifier("g_variant_iter_next_value")); iter_call.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(subiter_name))); var cforcond = new CCodeBinaryExpression(CCodeBinaryOperator.INEQUALITY, new CCodeAssignment(new CCodeIdentifier(element_name), iter_call), new CCodeConstant("NULL")); var cforiter = new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier("%s_length%d".printf(temp_name, dim))); ccode.open_for(null, cforcond, cforiter); if (dim < array_type.rank) { deserialize_array_dim(array_type, dim + 1, temp_name, new CCodeIdentifier(element_name), expr); } else { var size_check = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, new CCodeIdentifier(temp_name + "_size"), new CCodeIdentifier(temp_name + "_length")); ccode.open_if(size_check); // tmp_size = (2 * tmp_size); var new_size = new CCodeBinaryExpression(CCodeBinaryOperator.MUL, new CCodeConstant("2"), new CCodeIdentifier(temp_name + "_size")); ccode.add_assignment(new CCodeIdentifier(temp_name + "_size"), new_size); var renew_call = new CCodeFunctionCall(new CCodeIdentifier("g_renew")); renew_call.add_argument(new CCodeIdentifier(get_ccode_name(array_type.element_type))); renew_call.add_argument(new CCodeIdentifier(temp_name)); // add one extra element for NULL-termination renew_call.add_argument(new CCodeBinaryExpression(CCodeBinaryOperator.PLUS, new CCodeIdentifier(temp_name + "_size"), new CCodeConstant("1"))); ccode.add_assignment(new CCodeIdentifier(temp_name), renew_call); ccode.close(); var element_access = new CCodeElementAccess(new CCodeIdentifier(temp_name), new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier(temp_name + "_length"))); bool may_fail; var element_expr = deserialize_expression(array_type.element_type, new CCodeIdentifier(element_name), null, out may_fail, null); ccode.add_assignment(element_access, element_expr); } var unref = new CCodeFunctionCall(new CCodeIdentifier("g_variant_unref")); unref.add_argument(new CCodeIdentifier(element_name)); ccode.add_expression(unref); ccode.close(); if (expr != null) { ccode.add_assignment(get_array_length(expr, dim), new CCodeIdentifier("%s_length%d".printf(temp_name, dim))); } }
private void add_get_property_function(Class cl) { var get_prop = new CCodeFunction("_vala_%s_get_property".printf(get_ccode_lower_case_name(cl, null)), "void"); get_prop.modifiers = CCodeModifiers.STATIC; get_prop.add_parameter(new CCodeParameter("object", "GObject *")); get_prop.add_parameter(new CCodeParameter("property_id", "guint")); get_prop.add_parameter(new CCodeParameter("value", "GValue *")); get_prop.add_parameter(new CCodeParameter("pspec", "GParamSpec *")); push_function(get_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.get_accessor == null || prop.is_abstract) { continue; } if (!is_gobject_property(prop)) { // don't register private properties 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.get_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.get_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.get_accessor)); } else { // use the static real function as helper cfunc = new CCodeIdentifier(get_ccode_real_name(prop.get_accessor)); } ccode.add_case(new CCodeIdentifier(get_ccode_upper_case_name(prop))); if (prop.property_type.is_real_struct_type()) { var st = prop.property_type.data_type as Struct; ccode.open_block(); ccode.add_declaration(get_ccode_name(st), new CCodeVariableDeclarator("boxed")); ccall = new CCodeFunctionCall(cfunc); ccall.add_argument(cself); var boxed_addr = new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier("boxed")); ccall.add_argument(boxed_addr); ccode.add_expression(ccall); var csetcall = new CCodeFunctionCall(); csetcall.call = get_value_setter_function(prop.property_type); csetcall.add_argument(new CCodeIdentifier("value")); csetcall.add_argument(boxed_addr); add_guarded_expression(prop, csetcall); if (requires_destroy(prop.get_accessor.value_type)) { ccode.add_expression(destroy_value(new GLibValue(prop.get_accessor.value_type, new CCodeIdentifier("boxed"), true))); } ccode.close(); } else { ccall = new CCodeFunctionCall(cfunc); ccall.add_argument(cself); var array_type = prop.property_type as ArrayType; if (array_type != null && array_type.element_type.data_type == string_type.data_type) { // G_TYPE_STRV ccode.open_block(); ccode.add_declaration("int", new CCodeVariableDeclarator("length")); ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier("length"))); } var csetcall = new CCodeFunctionCall(); if (prop.get_accessor.value_type.value_owned) { csetcall.call = get_value_taker_function(prop.property_type); } else { csetcall.call = get_value_setter_function(prop.property_type); } csetcall.add_argument(new CCodeIdentifier("value")); csetcall.add_argument(ccall); add_guarded_expression(prop, csetcall); if (array_type != null && array_type.element_type.data_type == string_type.data_type) { ccode.close(); } } ccode.add_break(); } ccode.add_default(); emit_invalid_property_id_warn(); ccode.add_break(); ccode.close(); pop_function(); cfile.add_function_declaration(get_prop); cfile.add_function(get_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(); }
/* 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); }
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_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(); }