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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
29 * The link between an assignment and generated code.
31 public class Vala
.CCodeAssignmentModule
: CCodeMemberAccessModule
{
32 public CCodeAssignmentModule (CCodeGenerator codegen
, CCodeModule? 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
);
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
;
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
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 ();
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
));
135 Report
.error (assignment
.source_reference
, "internal error: unsupported element access");
136 assignment
.error
= true;
141 CCodeExpression
emit_simple_assignment (Assignment assignment
) {
142 CCodeExpression rhs
= (CCodeExpression
) assignment
.right
.ccodenode
;
144 bool unref_old
= requires_destroy (assignment
.left
.value_type
);
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
));
162 /* unref old value */
163 ccomma
.append_expression (get_unref_expression ((CCodeExpression
) get_ccodenode (assignment
.left
), assignment
.left
.value_type
, assignment
.left
));
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
));
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
);
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;
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
);
254 assignment
.ccodenode
= emit_simple_assignment (assignment
);