Line data Source code
1 : /* valaassignment.vala
2 : *
3 : * Copyright (C) 2006-2011 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 :
24 : /**
25 : * Represents an assignment expression in the source code.
26 : *
27 : * Supports =, |=, &=, ^=, +=, -=, *=, /=, %=, <<=, >>=.
28 : */
29 218980 : public class Vala.Assignment : Expression {
30 : /**
31 : * Left hand side of the assignment.
32 : */
33 : public Expression left {
34 5609984 : get { return _left; }
35 217444 : private set {
36 446798 : _left = value;
37 217444 : _left.parent_node = this;
38 : }
39 : }
40 :
41 : /**
42 : * Assignment operator.
43 : */
44 220866 : public AssignmentOperator operator { get; private set; }
45 :
46 : /**
47 : * Right hand side of the assignment.
48 : */
49 : public Expression right {
50 3480081 : get { return _right; }
51 227931 : private set {
52 455862 : _right = value;
53 227931 : _right.parent_node = this;
54 : }
55 : }
56 :
57 217443 : private Expression _left;
58 217443 : private Expression _right;
59 :
60 : /**
61 : * Creates a new assignment.
62 : *
63 : * @param left left hand side
64 : * @param operator assignment operator
65 : * @param right right hand side
66 : * @param source_reference reference to source code
67 : * @return newly created assignment
68 : */
69 652329 : public Assignment (Expression left, Expression right, AssignmentOperator operator = AssignmentOperator.SIMPLE, SourceReference? source_reference = null) {
70 217443 : this.right = right;
71 217443 : this.operator = operator;
72 217443 : this.source_reference = source_reference;
73 217443 : this.left = left;
74 : }
75 :
76 601836 : public override void accept (CodeVisitor visitor) {
77 601836 : visitor.visit_assignment (this);
78 :
79 601836 : visitor.visit_expression (this);
80 : }
81 :
82 601830 : public override void accept_children (CodeVisitor visitor) {
83 601830 : left.accept (visitor);
84 601830 : right.accept (visitor);
85 : }
86 :
87 0 : public override string to_string () {
88 0 : return "(%s %s %s)".printf (_left.to_string (), operator.to_string (), _right.to_string ());
89 : }
90 :
91 7403 : public override void replace_expression (Expression old_node, Expression new_node) {
92 7403 : if (left == old_node) {
93 1 : left = new_node;
94 : }
95 7403 : if (right == old_node) {
96 7402 : right = new_node;
97 : }
98 : }
99 :
100 0 : public override bool is_pure () {
101 0 : return false;
102 : }
103 :
104 0 : public override bool is_accessible (Symbol sym) {
105 0 : return left.is_accessible (sym) && right.is_accessible (sym);
106 : }
107 :
108 367970 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
109 367970 : left.get_error_types (collection, source_reference);
110 367970 : right.get_error_types (collection, source_reference);
111 : }
112 :
113 210224 : public override bool check (CodeContext context) {
114 210224 : if (checked) {
115 1454 : return !error;
116 : }
117 :
118 208770 : checked = true;
119 :
120 208770 : if (left is Tuple && operator == AssignmentOperator.SIMPLE && parent_node is ExpressionStatement) {
121 2 : unowned Tuple tuple = (Tuple) left;
122 :
123 2 : var local = new LocalVariable (null, get_temp_name (), right, right.source_reference);
124 2 : var decl = new DeclarationStatement (local, source_reference);
125 2 : insert_statement (context.analyzer.insert_block, decl);
126 2 : decl.check (context);
127 :
128 2 : int i = 0;
129 2 : ExpressionStatement stmt = null;
130 10 : foreach (var expr in tuple.get_expressions ()) {
131 4 : if (stmt != null) {
132 2 : insert_statement (context.analyzer.insert_block, stmt);
133 2 : stmt.check (context);
134 : }
135 :
136 4 : var temp_access = new MemberAccess.simple (local.name, right.source_reference);
137 4 : var ea = new ElementAccess (temp_access, expr.source_reference);
138 4 : ea.append_index (new IntegerLiteral (i.to_string (), expr.source_reference));
139 4 : var assign = new Assignment (expr, ea, operator, expr.source_reference);
140 4 : stmt = new ExpressionStatement (assign, expr.source_reference);
141 :
142 4 : i++;
143 : }
144 :
145 2 : context.analyzer.replaced_nodes.add (this);
146 2 : parent_node.replace_expression (this, stmt.expression);
147 2 : return stmt.expression.check (context);
148 : }
149 :
150 208768 : left.lvalue = true;
151 :
152 208768 : if (!left.check (context)) {
153 : // skip on error in inner expression
154 18 : error = true;
155 18 : return false;
156 : }
157 :
158 208750 : if (left is MemberAccess) {
159 205812 : unowned MemberAccess ma = (MemberAccess) left;
160 :
161 205812 : check_constant_assignment (ma);
162 :
163 205812 : if ((!(ma.symbol_reference is DynamicProperty) && ma.value_type == null) ||
164 205812 : (ma.inner == null && ma.member_name == "this" && context.analyzer.is_in_instance_method ())) {
165 1 : error = true;
166 1 : Report.error (source_reference, "unsupported lvalue in assignment");
167 1 : return false;
168 : }
169 205811 : if (ma.prototype_access) {
170 0 : error = true;
171 0 : Report.error (source_reference, "Access to instance member `%s' denied", ma.symbol_reference.get_full_name ());
172 0 : return false;
173 : }
174 :
175 205811 : if (ma.error || ma.symbol_reference == null) {
176 0 : error = true;
177 : /* if no symbol found, skip this check */
178 0 : return false;
179 : }
180 :
181 205811 : if (ma.symbol_reference.has_attribute ("GtkChild")) {
182 3 : error = true;
183 3 : Report.error (source_reference, "Assignment of [GtkChild] `%s' is not allowed", ma.symbol_reference.get_full_name ());
184 3 : return false;
185 : }
186 :
187 205808 : if (ma.symbol_reference is DynamicProperty) {
188 : // target_type not available for dynamic properties
189 : } else {
190 205805 : right.formal_target_type = ma.formal_value_type.copy ();
191 205805 : right.target_type = ma.value_type.copy ();
192 : }
193 2938 : } else if (left is ElementAccess) {
194 1517 : unowned ElementAccess ea = (ElementAccess) left;
195 :
196 3034 : check_constant_assignment (ea.container as MemberAccess);
197 :
198 1517 : if (ea.container.value_type.type_symbol == context.analyzer.string_type.type_symbol) {
199 0 : error = true;
200 0 : Report.error (ea.source_reference, "strings are immutable");
201 0 : return false;
202 1517 : } else if (ea.container.value_type.get_member ("set") is Method) {
203 13 : var set_call = new MethodCall (new MemberAccess (ea.container, "set", source_reference), source_reference);
204 39 : foreach (Expression e in ea.get_indices ()) {
205 13 : set_call.add_argument (e);
206 : }
207 :
208 17 : if (operator != AssignmentOperator.SIMPLE && ea.container.value_type.get_member ("get") is Method) {
209 : // transform into binary expression inside set call
210 4 : var get_call = new MethodCall (new MemberAccess (ea.container, "get", source_reference), source_reference);
211 12 : foreach (Expression e in ea.get_indices ()) {
212 4 : get_call.add_argument (e);
213 : }
214 :
215 : BinaryOperator bop;
216 :
217 4 : switch (operator) {
218 : case AssignmentOperator.BITWISE_OR: bop = BinaryOperator.BITWISE_OR; break;
219 : case AssignmentOperator.BITWISE_AND: bop = BinaryOperator.BITWISE_AND; break;
220 : case AssignmentOperator.BITWISE_XOR: bop = BinaryOperator.BITWISE_XOR; break;
221 : case AssignmentOperator.ADD: bop = BinaryOperator.PLUS; break;
222 : case AssignmentOperator.SUB: bop = BinaryOperator.MINUS; break;
223 : case AssignmentOperator.MUL: bop = BinaryOperator.MUL; break;
224 : case AssignmentOperator.DIV: bop = BinaryOperator.DIV; break;
225 : case AssignmentOperator.PERCENT: bop = BinaryOperator.MOD; break;
226 : case AssignmentOperator.SHIFT_LEFT: bop = BinaryOperator.SHIFT_LEFT; break;
227 : case AssignmentOperator.SHIFT_RIGHT: bop = BinaryOperator.SHIFT_RIGHT; break;
228 : default:
229 0 : error = true;
230 0 : Report.error (source_reference, "internal error: unsupported assignment operator");
231 0 : return false;
232 : }
233 :
234 4 : right = new BinaryExpression (bop, get_call, right, source_reference);
235 : }
236 :
237 13 : set_call.add_argument (right);
238 13 : parent_node.replace_expression (this, set_call);
239 13 : return set_call.check (context);
240 : } else {
241 1504 : right.target_type = left.value_type.copy ();
242 : }
243 1421 : } else if (left is PointerIndirection) {
244 1420 : right.target_type = left.value_type.copy ();
245 1 : } else if (left is Literal) {
246 1 : error = true;
247 1 : Report.error (source_reference, "Literals are immutable");
248 1 : return false;
249 : } else {
250 0 : error = true;
251 0 : Report.error (source_reference, "unsupported lvalue in assignment");
252 0 : return false;
253 : }
254 :
255 208732 : if (!right.check (context)) {
256 : // skip on error in inner expression
257 0 : error = true;
258 0 : return false;
259 : }
260 :
261 208732 : unowned MemberAccess? ma = left as MemberAccess;
262 208732 : unowned ElementAccess? ea = left as ElementAccess;
263 208732 : bool transform_assignment = false;
264 :
265 208732 : if (ma != null && !(ma.symbol_reference is LocalVariable)) {
266 : transform_assignment = true;
267 129687 : } else if (left.value_type != null && !left.value_type.is_non_null_simple_type ()) {
268 : transform_assignment = true;
269 99189 : } else if (ea != null && ea.container.value_type is ArrayType) {
270 : // check if the left is an array and its element is non-null simple type
271 61 : unowned ArrayType array_type = (ArrayType) ea.container.value_type;
272 61 : transform_assignment = !array_type.element_type.is_non_null_simple_type ();
273 : }
274 :
275 211814 : if ((operator != AssignmentOperator.SIMPLE) && transform_assignment) {
276 : // transform into simple assignment
277 : // FIXME: only do this if the backend doesn't support
278 : // the assignment natively
279 3082 : Expression old_value = null;
280 :
281 3082 : if (ma != null) {
282 3076 : old_value = new MemberAccess (ma.inner, ma.member_name, left.source_reference);
283 12 : } else if (ea !=null) {
284 6 : old_value = new ElementAccess (ea.container, left.source_reference);
285 6 : var indices = ea.get_indices ();
286 18 : foreach (var index in indices) {
287 6 : ((ElementAccess) old_value).append_index (index);
288 : }
289 : } else {
290 0 : assert_not_reached ();
291 : }
292 :
293 : BinaryOperator bop;
294 :
295 3082 : switch (operator) {
296 : case AssignmentOperator.BITWISE_OR: bop = BinaryOperator.BITWISE_OR; break;
297 : case AssignmentOperator.BITWISE_AND: bop = BinaryOperator.BITWISE_AND; break;
298 : case AssignmentOperator.BITWISE_XOR: bop = BinaryOperator.BITWISE_XOR; break;
299 : case AssignmentOperator.ADD: bop = BinaryOperator.PLUS; break;
300 : case AssignmentOperator.SUB: bop = BinaryOperator.MINUS; break;
301 : case AssignmentOperator.MUL: bop = BinaryOperator.MUL; break;
302 : case AssignmentOperator.DIV: bop = BinaryOperator.DIV; break;
303 : case AssignmentOperator.PERCENT: bop = BinaryOperator.MOD; break;
304 : case AssignmentOperator.SHIFT_LEFT: bop = BinaryOperator.SHIFT_LEFT; break;
305 : case AssignmentOperator.SHIFT_RIGHT: bop = BinaryOperator.SHIFT_RIGHT; break;
306 : default:
307 0 : error = true;
308 0 : Report.error (source_reference, "internal error: unsupported assignment operator");
309 0 : return false;
310 : }
311 :
312 3082 : var bin = new BinaryExpression (bop, old_value, right, source_reference);
313 3082 : bin.target_type = right.target_type;
314 3082 : right.target_type = right.target_type.copy ();
315 3082 : right.target_type.value_owned = false;
316 :
317 3082 : right = bin;
318 3082 : right.check (context);
319 :
320 3082 : operator = AssignmentOperator.SIMPLE;
321 : }
322 :
323 208732 : if (ma != null) {
324 205808 : if (ma.symbol_reference is Property) {
325 1477 : unowned Property prop = (Property) ma.symbol_reference;
326 1477 : if (right.value_type == null) {
327 1 : error = true;
328 1 : Report.error (source_reference, "Assignment: Invalid assignment attempt");
329 1 : return false;
330 : }
331 :
332 1476 : unowned DynamicProperty? dynamic_prop = prop as DynamicProperty;
333 3 : if (dynamic_prop != null) {
334 3 : dynamic_prop.property_type = right.value_type.copy ();
335 3 : left.value_type = dynamic_prop.property_type.copy ();
336 : }
337 204331 : } else if (ma.symbol_reference is ArrayLengthField && ((ArrayType) ma.inner.value_type).inline_allocated) {
338 1 : error = true;
339 1 : Report.error (source_reference, "`length' field of fixed length arrays is read-only");
340 1 : return false;
341 204330 : } else if (ma.symbol_reference is Variable && right.value_type is MethodType) {
342 18 : unowned Variable variable = (Variable) ma.symbol_reference;
343 :
344 18 : if (variable.variable_type is DelegateType) {
345 : /* check whether method matches callback type */
346 18 : if (!right.value_type.compatible (variable.variable_type)) {
347 2 : unowned Method m = (Method) right.symbol_reference;
348 2 : unowned Delegate cb = ((DelegateType) variable.variable_type).delegate_symbol;
349 2 : error = true;
350 2 : Report.error (source_reference, "Declaration of method `%s' is not compatible with delegate `%s'", m.get_full_name (), cb.get_full_name ());
351 2 : return false;
352 : }
353 : } else {
354 0 : error = true;
355 0 : Report.error (source_reference, "Assignment: Invalid assignment attempt");
356 0 : return false;
357 : }
358 204312 : } else if (ma.symbol_reference is Variable && right.value_type == null) {
359 1 : error = true;
360 1 : Report.error (source_reference, "Assignment: Invalid assignment attempt");
361 1 : return false;
362 204311 : } else if (ma.symbol_reference is Variable) {
363 204310 : unowned Variable variable = (Variable) ma.symbol_reference;
364 204310 : unowned ArrayType? variable_array_type = variable.variable_type as ArrayType;
365 231 : if (variable_array_type != null && variable_array_type.inline_allocated
366 6 : && right is ArrayCreationExpression && ((ArrayCreationExpression) right).initializer_list == null) {
367 1 : Report.warning (source_reference, "Inline allocated arrays don't require an explicit instantiation");
368 1 : ((Block) parent_node.parent_node).replace_statement ((Statement) parent_node, new EmptyStatement (source_reference));
369 1 : return true;
370 : }
371 : }
372 :
373 205802 : if (left.value_type != null && right.value_type != null) {
374 : /* if there was an error on either side,
375 : * i.e. {left|right}.value_type == null, skip type check */
376 :
377 205802 : if (!right.value_type.compatible (left.value_type)) {
378 0 : error = true;
379 0 : Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'", right.value_type.to_string (), left.value_type.to_string ());
380 0 : return false;
381 205802 : } else if (left.value_type is EnumValueType && right.value_type is IntegerType
382 8 : && (!(right is IntegerLiteral) || ((IntegerLiteral) right).value != "0")) {
383 : //FIXME This will have to be an error in the future?
384 1 : Report.notice (source_reference, "Assignment: Unsafe conversion from `%s' to `%s'", right.value_type.to_string (), left.value_type.to_string ());
385 : }
386 :
387 205802 : if (!(ma.symbol_reference is Property)) {
388 204326 : if (right.value_type.is_disposable ()) {
389 : /* rhs transfers ownership of the expression */
390 3354 : if (!(left.value_type is PointerType) && !left.value_type.value_owned) {
391 : /* lhs doesn't own the value */
392 0 : error = true;
393 0 : Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
394 : }
395 200972 : } else if (left.value_type.value_owned) {
396 : /* lhs wants to own the value
397 : * rhs doesn't transfer the ownership
398 : * code generator needs to add reference
399 : * increment calls */
400 : }
401 : }
402 : }
403 :
404 205802 : unowned MemberAccess? right_ma = right as MemberAccess;
405 29588 : if (right_ma != null && ma.symbol_reference == right_ma.symbol_reference) {
406 69 : if (ma.symbol_reference is LocalVariable || ma.symbol_reference is Parameter) {
407 1 : Report.warning (source_reference, "Assignment to same variable");
408 68 : } else if (ma.symbol_reference is Field) {
409 24 : unowned Field f = (Field) ma.symbol_reference;
410 24 : if (f.binding == MemberBinding.STATIC) {
411 1 : Report.warning (source_reference, "Assignment to same variable");
412 : } else {
413 23 : unowned MemberAccess? ma_inner = ma.inner as MemberAccess;
414 23 : unowned MemberAccess? right_ma_inner = right_ma.inner as MemberAccess;
415 23 : if (ma_inner != null && ma_inner.member_name == "this" && ma_inner.inner == null &&
416 1 : right_ma_inner != null && right_ma_inner.member_name == "this" && right_ma_inner.inner == null) {
417 1 : Report.warning (source_reference, "Assignment to same variable");
418 : }
419 : }
420 : }
421 : }
422 2924 : } else if (ea != null) {
423 1504 : if (!right.value_type.compatible (left.value_type)) {
424 1 : error = true;
425 1 : Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'", right.value_type.to_string (), left.value_type.to_string ());
426 1 : return false;
427 : }
428 :
429 2925 : if (right.value_type.is_disposable ()) {
430 : /* rhs transfers ownership of the expression */
431 :
432 : DataType element_type;
433 :
434 1423 : if (ea.container.value_type is ArrayType) {
435 1423 : unowned ArrayType array_type = (ArrayType) ea.container.value_type;
436 1423 : element_type = array_type.element_type;
437 : } else {
438 0 : var args = ea.container.value_type.get_type_arguments ();
439 0 : assert (args.size == 1);
440 0 : element_type = args.get (0);
441 : }
442 :
443 1423 : if (!(element_type is PointerType) && !element_type.value_owned) {
444 : /* lhs doesn't own the value */
445 1 : error = true;
446 1 : Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
447 1 : return false;
448 : }
449 80 : } else if (left.value_type.value_owned) {
450 : /* lhs wants to own the value
451 : * rhs doesn't transfer the ownership
452 : * code generator needs to add reference
453 : * increment calls */
454 : }
455 : } else {
456 1421 : return true;
457 : }
458 :
459 207304 : if (left.value_type != null) {
460 207304 : value_type = left.value_type.copy ();
461 207304 : value_type.value_owned = false;
462 : } else {
463 0 : value_type = null;
464 : }
465 :
466 207304 : if (value_type != null) {
467 207304 : value_type.check (context);
468 : }
469 :
470 207304 : return !error;
471 : }
472 :
473 11308 : bool is_array_add () {
474 11308 : unowned BinaryExpression? binary = right as BinaryExpression;
475 1445 : if (binary != null && binary.left.value_type is ArrayType) {
476 69 : if (binary.operator == BinaryOperator.PLUS) {
477 65 : if (left.symbol_reference == binary.left.symbol_reference) {
478 : // Allow direct access to array variable
479 65 : binary.left.lvalue = true;
480 65 : return true;
481 : }
482 : }
483 : }
484 :
485 11308 : return false;
486 : }
487 :
488 207329 : void check_constant_assignment (MemberAccess? inner) {
489 215196 : while (inner != null) {
490 215196 : if (inner.symbol_reference is Constant) {
491 3 : error = true;
492 3 : Report.error (source_reference, "Assignment to constant after initialization");
493 3 : break;
494 : }
495 215193 : if (inner.inner is MemberAccess) {
496 7866 : inner = (MemberAccess) inner.inner;
497 207327 : } else if (inner.inner is ElementAccess) {
498 1 : inner = ((ElementAccess) inner.inner).container as MemberAccess;
499 : } else {
500 : inner = null;
501 : }
502 : }
503 : }
504 :
505 12971 : public override void emit (CodeGenerator codegen) {
506 12971 : unowned MemberAccess? ma = left as MemberAccess;
507 12971 : unowned ElementAccess? ea = left as ElementAccess;
508 12971 : unowned PointerIndirection? pi = left as PointerIndirection;
509 12971 : if (ma != null) {
510 12878 : unowned LocalVariable? local = ma.symbol_reference as LocalVariable;
511 12878 : unowned Parameter? param = ma.symbol_reference as Parameter;
512 12878 : unowned Field? field = ma.symbol_reference as Field;
513 12878 : unowned Property? property = ma.symbol_reference as Property;
514 :
515 12878 : bool instance = (field != null && field.binding != MemberBinding.STATIC)
516 10809 : || (property != null && property.binding != MemberBinding.STATIC);
517 :
518 12878 : if (operator == AssignmentOperator.SIMPLE &&
519 12784 : (local != null || param != null || field != null) &&
520 11308 : !is_array_add () &&
521 11243 : !(field is ArrayLengthField) &&
522 11198 : !(field is DelegateTargetField) &&
523 11196 : !(field is DelegateDestroyField) &&
524 11194 : !(left.value_type.is_real_non_null_struct_type () && right is ObjectCreationExpression)) {
525 : // visit_assignment not necessary
526 11188 : if (instance && ma.inner != null) {
527 1981 : ma.inner.emit (codegen);
528 : }
529 :
530 11188 : right.emit (codegen);
531 11188 : var new_value = right.target_value;
532 :
533 11188 : if (local != null) {
534 8561 : codegen.store_local (local, new_value, false, source_reference);
535 2627 : } else if (param != null) {
536 326 : codegen.store_parameter (param, new_value, false, source_reference);
537 2301 : } else if (field != null) {
538 2621 : codegen.store_field (field, instance && ma.inner != null ? ma.inner.target_value : null, new_value, false, source_reference);
539 : }
540 :
541 11188 : if (!(parent_node is ExpressionStatement)) {
542 : // when load_variable is changed to use temporary
543 : // variables, replace following code with this line
544 : // target_value = new_value;
545 56 : if (local != null) {
546 48 : target_value = codegen.load_local (local);
547 8 : } else if (param != null) {
548 0 : target_value = codegen.load_parameter (param);
549 8 : } else if (field != null) {
550 8 : target_value = codegen.load_field (field, instance && ma.inner != null ? ma.inner.target_value : null);
551 : }
552 : }
553 :
554 11188 : codegen.visit_expression (this);
555 11188 : return;
556 : }
557 :
558 1690 : if (instance && ma.inner != null && property != null) {
559 1469 : ma.inner.emit (codegen);
560 221 : } else if (property == null) {
561 : // always process full lvalue
562 : // current codegen depends on it
563 : // should be removed when moving codegen from
564 : // visit_assignment to emit_store_field/local/param
565 214 : ma.emit (codegen);
566 : }
567 93 : } else if (ea != null) {
568 : // always process full lvalue
569 : // current codegen depends on it
570 : // should be removed when moving codegen from
571 : // visit_assignment to emit_store_element
572 88 : ea.emit (codegen);
573 5 : } else if (pi != null) {
574 : // always process full lvalue
575 : // current codegen depends on it
576 : // should be removed when moving codegen from
577 : // visit_assignment to emit_store_indirectZ
578 5 : pi.emit (codegen);
579 : }
580 :
581 1783 : right.emit (codegen);
582 :
583 1783 : codegen.visit_assignment (this);
584 :
585 1783 : codegen.visit_expression (this);
586 : }
587 :
588 437403 : public override void get_defined_variables (Collection<Variable> collection) {
589 437403 : right.get_defined_variables (collection);
590 437403 : left.get_defined_variables (collection);
591 437403 : unowned LocalVariable? local = left.symbol_reference as LocalVariable;
592 437403 : unowned Parameter? param = left.symbol_reference as Parameter;
593 437403 : if (local != null) {
594 266346 : collection.add (local);
595 171057 : } else if (param != null && param.direction == ParameterDirection.OUT) {
596 95682 : collection.add (param);
597 : }
598 : }
599 :
600 145801 : public override void get_used_variables (Collection<Variable> collection) {
601 145801 : unowned MemberAccess? ma = left as MemberAccess;
602 145801 : unowned ElementAccess? ea = left as ElementAccess;
603 145801 : if (ma != null && ma.inner != null) {
604 6365 : ma.inner.get_used_variables (collection);
605 139436 : } else if (ea != null) {
606 1050 : ea.get_used_variables (collection);
607 : }
608 145801 : right.get_used_variables (collection);
609 : }
610 : }
611 :
612 : public enum Vala.AssignmentOperator {
613 : NONE,
614 : SIMPLE,
615 : BITWISE_OR,
616 : BITWISE_AND,
617 : BITWISE_XOR,
618 : ADD,
619 : SUB,
620 : MUL,
621 : DIV,
622 : PERCENT,
623 : SHIFT_LEFT,
624 : SHIFT_RIGHT;
625 :
626 : public unowned string to_string () {
627 0 : switch (this) {
628 0 : case SIMPLE: return "=";
629 0 : case BITWISE_OR: return "|=";
630 0 : case BITWISE_AND: return "&=";
631 0 : case BITWISE_XOR: return "^=";
632 0 : case ADD: return "+=";
633 0 : case SUB: return "-=";
634 0 : case MUL: return "*=";
635 0 : case DIV: return "/=";
636 0 : case PERCENT: return "%=";
637 0 : case SHIFT_LEFT: return "<<=";
638 0 : case SHIFT_RIGHT: return ">>=";
639 0 : default: assert_not_reached ();
640 : }
641 : }
642 : }
|