codegen: Use temporary variable for string concatenation
[vala-lang.git] / codegen / valadovamemberaccessmodule.vala
blob9fa27aac7d26f1f36b4a91ddcf6ec207bc4fbf49
1 /* valadovamemberaccessmodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 public abstract class Vala.DovaMemberAccessModule : DovaControlFlowModule {
26 public override void visit_member_access (MemberAccess expr) {
27 CCodeExpression pub_inst = null;
28 DataType base_type = null;
30 if (expr.inner != null) {
31 pub_inst = get_cvalue (expr.inner);
33 if (expr.inner.value_type != null) {
34 base_type = expr.inner.value_type;
38 if (expr.symbol_reference is Method) {
39 var m = (Method) expr.symbol_reference;
41 if (!(m is DynamicMethod)) {
42 generate_method_declaration (m, cfile);
44 if (!m.external && m.external_package) {
45 // internal VAPI methods
46 // only add them once per source file
47 if (add_generated_external_symbol (m)) {
48 visit_method (m);
53 if (expr.inner is BaseAccess) {
54 if (m.base_method != null) {
55 var base_class = (Class) m.base_method.parent_symbol;
57 set_cvalue (expr, new CCodeIdentifier ("%s_base_%s".printf (base_class.get_lower_case_cname (null), m.name)));
58 return;
59 } else if (m.base_interface_method != null) {
60 var base_iface = (Interface) m.base_interface_method.parent_symbol;
62 set_cvalue (expr, new CCodeIdentifier ("%s_base_%s".printf (base_iface.get_lower_case_cname (null), m.name)));
63 return;
67 if (m.base_method != null) {
68 if (!method_has_wrapper (m.base_method)) {
69 var inst = pub_inst;
70 if (expr.inner != null && !expr.inner.is_pure ()) {
71 // instance expression has side-effects
72 // store in temp. variable
73 var temp_var = get_temp_variable (expr.inner.value_type);
74 emit_temp_var (temp_var);
75 var ctemp = new CCodeIdentifier (temp_var.name);
76 inst = new CCodeAssignment (ctemp, pub_inst);
77 set_cvalue (expr.inner, ctemp);
79 var base_class = (Class) m.base_method.parent_symbol;
80 var vclass = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (base_class.get_upper_case_cname (null))));
81 vclass.add_argument (inst);
82 set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, m.name));
83 } else {
84 set_cvalue (expr, new CCodeIdentifier (m.base_method.get_cname ()));
86 } else if (m.base_interface_method != null) {
87 set_cvalue (expr, new CCodeIdentifier (m.base_interface_method.get_cname ()));
88 } else if (m is CreationMethod) {
89 set_cvalue (expr, new CCodeIdentifier (m.get_real_cname ()));
90 } else {
91 set_cvalue (expr, new CCodeIdentifier (m.get_cname ()));
93 } else if (expr.symbol_reference is ArrayLengthField) {
94 generate_property_accessor_declaration (((Property) array_class.scope.lookup ("length")).get_accessor, cfile);
96 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dova_array_get_length"));
97 ccall.add_argument (pub_inst);
98 set_cvalue (expr, ccall);
99 } else if (expr.symbol_reference is Field) {
100 var f = (Field) expr.symbol_reference;
101 expr.target_value = load_field (f, expr.inner);
102 } else if (expr.symbol_reference is EnumValue) {
103 var ev = (EnumValue) expr.symbol_reference;
105 generate_enum_declaration ((Enum) ev.parent_symbol, cfile);
107 set_cvalue (expr, new CCodeConstant (ev.get_cname ()));
108 } else if (expr.symbol_reference is Constant) {
109 var c = (Constant) expr.symbol_reference;
111 generate_constant_declaration (c, cfile);
113 set_cvalue (expr, new CCodeIdentifier (c.get_cname ()));
114 } else if (expr.symbol_reference is Property) {
115 var prop = (Property) expr.symbol_reference;
117 if (!(prop is DynamicProperty)) {
118 generate_property_accessor_declaration (prop.get_accessor, cfile);
120 if (!prop.external && prop.external_package) {
121 // internal VAPI properties
122 // only add them once per source file
123 if (add_generated_external_symbol (prop)) {
124 visit_property (prop);
129 if (expr.inner is BaseAccess) {
130 if (prop.base_property != null) {
131 var base_class = (Class) prop.base_property.parent_symbol;
132 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
133 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
135 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
136 ccall.add_argument (get_cvalue (expr.inner));
137 set_cvalue (expr, ccall);
138 return;
139 } else if (prop.base_interface_property != null) {
140 var base_iface = (Interface) prop.base_interface_property.parent_symbol;
141 string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
143 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "get_%s".printf (prop.name)));
144 ccall.add_argument (get_cvalue (expr.inner));
145 set_cvalue (expr, ccall);
146 return;
150 var base_property = prop;
151 if (prop.base_property != null) {
152 base_property = prop.base_property;
153 } else if (prop.base_interface_property != null) {
154 base_property = prop.base_interface_property;
156 string getter_cname = base_property.get_accessor.get_cname ();
157 var ccall = new CCodeFunctionCall (new CCodeIdentifier (getter_cname));
159 if (prop.binding == MemberBinding.INSTANCE) {
160 ccall.add_argument (pub_inst);
163 set_cvalue (expr, ccall);
164 } else if (expr.symbol_reference is LocalVariable) {
165 var local = (LocalVariable) expr.symbol_reference;
166 expr.target_value = load_local (local);
167 } else if (expr.symbol_reference is Parameter) {
168 var p = (Parameter) expr.symbol_reference;
169 expr.target_value = load_parameter (p);
173 public TargetValue get_local_cvalue (LocalVariable local) {
174 var result = new DovaValue (local.variable_type);
176 if (local.is_result) {
177 // used in postconditions
178 result.cvalue = new CCodeIdentifier ("result");
179 } else if (local.captured) {
180 // captured variables are stored on the heap
181 var block = (Block) local.parent_symbol;
182 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (local.name));
183 } else {
184 result.cvalue = get_variable_cexpression (local.name);
187 return result;
190 public TargetValue get_parameter_cvalue (Parameter p) {
191 var result = new DovaValue (p.variable_type);
193 if (p.name == "this") {
194 if (current_method != null && current_method.coroutine) {
195 // use closure
196 result.cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "this");
197 } else {
198 var st = current_type_symbol as Struct;
199 if (st != null && !st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type () && (!st.is_simple_type () || current_method is CreationMethod)) {
200 result.cvalue = new CCodeIdentifier ("(*this)");
201 } else {
202 result.cvalue = new CCodeIdentifier ("this");
205 } else {
206 if (p.captured) {
207 // captured variables are stored on the heap
208 var block = p.parent_symbol as Block;
209 if (block == null) {
210 block = ((Method) p.parent_symbol).body;
212 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (p.name));
213 } else {
214 if (current_method != null && current_method.coroutine) {
215 // use closure
216 result.cvalue = get_variable_cexpression (p.name);
217 } else {
218 var type_as_struct = p.variable_type.data_type as Struct;
219 if (p.direction != ParameterDirection.IN
220 || (type_as_struct != null && !type_as_struct.is_simple_type () && !p.variable_type.nullable)) {
221 if (p.variable_type is GenericType) {
222 result.cvalue = get_variable_cexpression (p.name);
223 } else {
224 result.cvalue = new CCodeIdentifier ("(*%s)".printf (get_variable_cname (p.name)));
226 } else {
227 // Property setters of non simple structs shall replace all occurences
228 // of the "value" formal parameter with a dereferencing version of that
229 // parameter.
230 if (current_property_accessor != null &&
231 current_property_accessor.writable &&
232 current_property_accessor.value_parameter == p &&
233 current_property_accessor.prop.property_type.is_real_struct_type ()) {
234 result.cvalue = new CCodeIdentifier ("(*value)");
235 } else {
236 result.cvalue = get_variable_cexpression (p.name);
243 return result;
246 public TargetValue get_field_cvalue (Field f, Expression? instance) {
247 var result = new DovaValue (f.variable_type);
249 if (f.binding == MemberBinding.INSTANCE) {
250 CCodeExpression pub_inst = null;
252 if (instance != null) {
253 pub_inst = get_cvalue (instance);
256 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) f.parent_symbol);
258 var cl = instance_target_type.data_type as Class;
259 bool dova_priv = false;
260 if ((f.access == SymbolAccessibility.PRIVATE || f.access == SymbolAccessibility.INTERNAL)) {
261 dova_priv = true;
264 CCodeExpression inst;
265 if (dova_priv) {
266 var priv_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (cl.get_upper_case_cname (null))));
267 priv_call.add_argument (pub_inst);
268 inst = priv_call;
269 } else {
270 inst = pub_inst;
272 if (instance_target_type.data_type.is_reference_type () || (instance != null && instance.value_type is PointerType)) {
273 result.cvalue = new CCodeMemberAccess.pointer (inst, f.get_cname ());
274 } else {
275 result.cvalue = new CCodeMemberAccess (inst, f.get_cname ());
277 } else {
278 generate_field_declaration (f, cfile);
280 result.cvalue = new CCodeIdentifier (f.get_cname ());
283 return result;
286 TargetValue load_variable (Variable variable, TargetValue value) {
287 return value;
290 public override TargetValue load_local (LocalVariable local) {
291 return load_variable (local, get_local_cvalue (local));
294 public TargetValue load_parameter (Parameter param) {
295 return load_variable (param, get_parameter_cvalue (param));
298 public TargetValue load_field (Field field, Expression? instance) {
299 return load_variable (field, get_field_cvalue (field, instance));