void add_struct_copy_function(Struct st) { var function = new CCodeFunction(get_ccode_copy_function(st), "void"); if (st.is_private_symbol()) { function.modifiers = CCodeModifiers.STATIC; } else if (context.hide_internal && st.is_internal_symbol()) { function.modifiers = CCodeModifiers.INTERNAL; } function.add_parameter(new CCodeParameter("self", "const " + get_ccode_name(st) + "*")); function.add_parameter(new CCodeParameter("dest", get_ccode_name(st) + "*")); push_function(function); var dest_struct = new GLibValue(get_data_type_for_symbol(st), new CCodeIdentifier("(*dest)"), true); foreach (var f in st.get_fields()) { if (f.binding == MemberBinding.INSTANCE) { var value = load_field(f, load_this_parameter((TypeSymbol)st)); if (requires_copy(f.variable_type)) { value = copy_value(value, f); if (value == null) { // error case, continue to avoid critical continue; } } store_field(f, dest_struct, value); } } pop_function(); cfile.add_function(function); }
/* 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); }
/* 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); }
/* 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); }
CCodeFunction generate_free_function(Method m) { var dataname = Symbol.lower_case_to_camel_case(get_ccode_name(m)) + "Data"; var freefunc = new CCodeFunction(get_ccode_real_name(m) + "_data_free", "void"); freefunc.modifiers = CCodeModifiers.STATIC; freefunc.add_parameter(new CCodeParameter("_data", "gpointer")); push_context(new EmitContext(m)); push_function(freefunc); ccode.add_declaration(dataname + "*", new CCodeVariableDeclarator("_data_", new CCodeIdentifier("_data"))); foreach (Parameter param in m.get_parameters()) { if (!param.captured && param.direction != ParameterDirection.OUT) { var param_type = param.variable_type.copy(); if (!param_type.value_owned) { param_type.value_owned = !no_implicit_copy(param_type); } if (requires_destroy(param_type)) { ccode.add_expression(destroy_parameter(param)); } } } if (requires_destroy(m.return_type)) { if (get_ccode_array_length(m) || !(m.return_type is ArrayType)) { /* this is very evil. */ var v = new LocalVariable(m.return_type, ".result"); ccode.add_expression(destroy_local(v)); } else { var v = new GLibValue(m.return_type, new CCodeIdentifier("_data_->result"), true); v.array_null_terminated = get_ccode_array_null_terminated(m); ccode.add_expression(destroy_value(v)); } } if (m.binding == MemberBinding.INSTANCE) { var this_type = m.this_parameter.variable_type.copy(); this_type.value_owned = true; if (requires_destroy(this_type)) { ccode.add_expression(destroy_parameter(m.this_parameter)); } } var freecall = new CCodeFunctionCall(new CCodeIdentifier("g_slice_free")); freecall.add_argument(new CCodeIdentifier(dataname)); freecall.add_argument(new CCodeIdentifier("_data_")); ccode.add_expression(freecall); pop_context(); cfile.add_function_declaration(freefunc); cfile.add_function(freefunc); return(freefunc); }