Support vfunc_name attribute
[vala-lang.git] / gobject / valaccodeassignmentmodule.vala
blob90eb3d601a5a2caaa5c51ba3d9d2ac71f3bb22e7
1 /* valaccodeassignmentmodule.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
26 using Gee;
28 /**
29 * The link between an assignment and generated code.
31 public class Vala.CCodeAssignmentModule : CCodeMemberAccessModule {
32 public CCodeAssignmentModule (CCodeGenerator codegen, CCodeModule? next) {
33 base (codegen, next);
36 CCodeExpression emit_property_assignment (Assignment assignment) {
37 var ma = assignment.left as MemberAccess;
39 var prop = (Property) assignment.left.symbol_reference;
41 if (prop.set_accessor.construction && current_type_symbol is Class && current_class.is_subtype_of (gobject_type) && in_creation_method) {
42 return head.get_construct_property_assignment (prop.get_canonical_cconstant (), prop.property_type, (CCodeExpression) assignment.right.ccodenode);
43 } else {
44 CCodeExpression cexpr = (CCodeExpression) assignment.right.ccodenode;
46 if (!prop.no_accessor_method) {
47 if (prop.property_type.is_real_struct_type ()) {
48 cexpr = get_address_of_expression (assignment.right, cexpr);
52 if (assignment.operator != AssignmentOperator.SIMPLE) {
53 CCodeBinaryOperator cop;
54 if (assignment.operator == AssignmentOperator.BITWISE_OR) {
55 cop = CCodeBinaryOperator.BITWISE_OR;
56 } else if (assignment.operator == AssignmentOperator.BITWISE_AND) {
57 cop = CCodeBinaryOperator.BITWISE_AND;
58 } else if (assignment.operator == AssignmentOperator.BITWISE_XOR) {
59 cop = CCodeBinaryOperator.BITWISE_XOR;
60 } else if (assignment.operator == AssignmentOperator.ADD) {
61 cop = CCodeBinaryOperator.PLUS;
62 } else if (assignment.operator == AssignmentOperator.SUB) {
63 cop = CCodeBinaryOperator.MINUS;
64 } else if (assignment.operator == AssignmentOperator.MUL) {
65 cop = CCodeBinaryOperator.MUL;
66 } else if (assignment.operator == AssignmentOperator.DIV) {
67 cop = CCodeBinaryOperator.DIV;
68 } else if (assignment.operator == AssignmentOperator.PERCENT) {
69 cop = CCodeBinaryOperator.MOD;
70 } else if (assignment.operator == AssignmentOperator.SHIFT_LEFT) {
71 cop = CCodeBinaryOperator.SHIFT_LEFT;
72 } else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
73 cop = CCodeBinaryOperator.SHIFT_RIGHT;
74 } else {
75 assert_not_reached ();
77 cexpr = new CCodeBinaryExpression (cop, (CCodeExpression) get_ccodenode (assignment.left), cexpr);
80 var ccall = get_property_set_call (prop, ma, cexpr);
82 // assignments are expressions, so return the current property value, except if we're sure that it can't be used
83 if (!(assignment.parent_node is ExpressionStatement)) {
84 var ccomma = new CCodeCommaExpression ();
85 ccomma.append_expression (ccall); // update property
86 ccomma.append_expression ((CCodeExpression) get_ccodenode (ma)); // current property value
88 return ccomma;
89 } else {
90 return ccall;
95 private CCodeExpression? emit_non_array_element_access (Assignment assignment) {
96 // custom element access
97 CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
99 var expr = (ElementAccess) assignment.left;
100 var container_type = expr.container.value_type.data_type;
101 Gee.List<Expression> indices = expr.get_indices ();
102 Iterator<Expression> indices_it = indices.iterator ();
103 indices_it.next ();
105 var ccontainer = (CCodeExpression) get_ccodenode (expr.container);
106 var cindex = (CCodeExpression) get_ccodenode (indices_it.get ());
108 if (container_type != null && list_type != null && map_type != null &&
109 (container_type.is_subtype_of (list_type) || container_type.is_subtype_of (map_type))) {
110 // lookup symbol in interface instead of class as implemented interface methods are not in VAPI files
111 TypeSymbol collection_iface = null;
112 if (container_type.is_subtype_of (list_type)) {
113 collection_iface = list_type;
114 } else if (container_type.is_subtype_of (map_type)) {
115 collection_iface = map_type;
117 var set_method = (Method) collection_iface.scope.lookup ("set");
118 Gee.List<FormalParameter> set_params = set_method.get_parameters ();
119 Iterator<FormalParameter> set_params_it = set_params.iterator ();
120 set_params_it.next ();
121 var set_param = set_params_it.get ();
123 if (set_param.parameter_type is GenericType) {
124 var index_type = SemanticAnalyzer.get_actual_type (expr.container.value_type, (GenericType) set_param.parameter_type, assignment);
125 cindex = convert_to_generic_pointer (cindex, index_type);
128 var set_ccall = new CCodeFunctionCall (new CCodeIdentifier (set_method.get_cname ()));
129 set_ccall.add_argument (new CCodeCastExpression (ccontainer, collection_iface.get_cname () + "*"));
130 set_ccall.add_argument (cindex);
131 set_ccall.add_argument (convert_to_generic_pointer (rhs, expr.value_type));
133 return set_ccall;
134 } else {
135 Report.error (assignment.source_reference, "internal error: unsupported element access");
136 assignment.error = true;
137 return null;
141 CCodeExpression emit_simple_assignment (Assignment assignment) {
142 CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
144 bool unref_old = requires_destroy (assignment.left.value_type);
145 bool array = false;
146 bool instance_delegate = false;
147 if (assignment.left.value_type is ArrayType) {
148 var array_field = assignment.left.symbol_reference as Field;
149 array = (array_field == null || !array_field.no_array_length);
150 } else if (assignment.left.value_type is DelegateType) {
151 var delegate_type = (DelegateType) assignment.left.value_type;
152 instance_delegate = delegate_type.delegate_symbol.has_target;
155 if (unref_old || array || instance_delegate) {
156 var ccomma = new CCodeCommaExpression ();
158 var temp_decl = get_temp_variable (assignment.left.value_type);
159 temp_vars.insert (0, temp_decl);
160 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), rhs));
161 if (unref_old) {
162 /* unref old value */
163 ccomma.append_expression (get_unref_expression ((CCodeExpression) get_ccodenode (assignment.left), assignment.left.value_type, assignment.left));
166 if (array) {
167 var array_type = (ArrayType) assignment.left.value_type;
168 for (int dim = 1; dim <= array_type.rank; dim++) {
169 var lhs_array_len = head.get_array_length_cexpression (assignment.left, dim);
170 var rhs_array_len = head.get_array_length_cexpression (assignment.right, dim);
171 ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
173 if (array_type.rank == 1) {
174 var array_var = assignment.left.symbol_reference;
175 if (array_var != null && array_var.is_internal_symbol ()
176 && (array_var is LocalVariable || array_var is Field)) {
177 var lhs_array_size = head.get_array_size_cexpression (assignment.left);
178 var rhs_array_len = head.get_array_length_cexpression (assignment.left, 1);
179 ccomma.append_expression (new CCodeAssignment (lhs_array_size, rhs_array_len));
182 } else if (instance_delegate) {
183 var lhs_delegate_target = get_delegate_target_cexpression (assignment.left);
184 var rhs_delegate_target = get_delegate_target_cexpression (assignment.right);
185 ccomma.append_expression (new CCodeAssignment (lhs_delegate_target, rhs_delegate_target));
188 ccomma.append_expression (get_variable_cexpression (temp_decl.name));
190 rhs = ccomma;
193 var cop = CCodeAssignmentOperator.SIMPLE;
194 if (assignment.operator == AssignmentOperator.BITWISE_OR) {
195 cop = CCodeAssignmentOperator.BITWISE_OR;
196 } else if (assignment.operator == AssignmentOperator.BITWISE_AND) {
197 cop = CCodeAssignmentOperator.BITWISE_AND;
198 } else if (assignment.operator == AssignmentOperator.BITWISE_XOR) {
199 cop = CCodeAssignmentOperator.BITWISE_XOR;
200 } else if (assignment.operator == AssignmentOperator.ADD) {
201 cop = CCodeAssignmentOperator.ADD;
202 } else if (assignment.operator == AssignmentOperator.SUB) {
203 cop = CCodeAssignmentOperator.SUB;
204 } else if (assignment.operator == AssignmentOperator.MUL) {
205 cop = CCodeAssignmentOperator.MUL;
206 } else if (assignment.operator == AssignmentOperator.DIV) {
207 cop = CCodeAssignmentOperator.DIV;
208 } else if (assignment.operator == AssignmentOperator.PERCENT) {
209 cop = CCodeAssignmentOperator.PERCENT;
210 } else if (assignment.operator == AssignmentOperator.SHIFT_LEFT) {
211 cop = CCodeAssignmentOperator.SHIFT_LEFT;
212 } else if (assignment.operator == AssignmentOperator.SHIFT_RIGHT) {
213 cop = CCodeAssignmentOperator.SHIFT_RIGHT;
216 CCodeExpression codenode = new CCodeAssignment ((CCodeExpression) get_ccodenode (assignment.left), rhs, cop);
218 if (unref_old && get_ccodenode (assignment.left) is CCodeElementAccess) {
219 // ensure that index expression in element access doesn't get evaluated more than once
220 // except when it's a simple expression
221 var cea = (CCodeElementAccess) get_ccodenode (assignment.left);
222 if (!(cea.index is CCodeConstant || cea.index is CCodeIdentifier)) {
223 var index_temp_decl = get_temp_variable (int_type);
224 temp_vars.insert (0, index_temp_decl);
226 var ccomma = new CCodeCommaExpression ();
227 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (index_temp_decl.name), cea.index));
228 ccomma.append_expression (codenode);
230 cea.index = get_variable_cexpression (index_temp_decl.name);
232 codenode = ccomma;
236 return codenode;
239 public override void visit_assignment (Assignment assignment) {
240 assignment.right.accept (codegen);
242 if (assignment.left.error || assignment.right.error) {
243 assignment.error = true;
244 return;
247 if (assignment.left.symbol_reference is Property) {
248 assignment.ccodenode = emit_property_assignment (assignment);
249 } else if (assignment.left is ElementAccess
250 && !(((ElementAccess) assignment.left).container.value_type is ArrayType)
251 && !(((ElementAccess) assignment.left).container.value_type is PointerType)) {
252 assignment.ccodenode = emit_non_array_element_access (assignment);
253 } else {
254 assignment.ccodenode = emit_simple_assignment (assignment);