~ubuntu-branches/ubuntu/raring/vala-0.20/raring-proposed

« back to all changes in this revision

Viewing changes to vala/valaassignment.vala

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher
  • Date: 2013-04-05 13:45:05 UTC
  • Revision ID: package-import@ubuntu.com-20130405134505-yyk3rec9904i7p8o
Tags: upstream-0.20.1
ImportĀ upstreamĀ versionĀ 0.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
public class Vala.Assignment : Expression {
 
30
        /**
 
31
         * Left hand side of the assignment.
 
32
         */
 
33
        public Expression left {
 
34
                get { return _left; }
 
35
                set {
 
36
                        _left = value;
 
37
                        _left.parent_node = this;
 
38
                }
 
39
        }
 
40
        
 
41
        /**
 
42
         * Assignment operator.
 
43
         */
 
44
        public AssignmentOperator operator { get; set; }
 
45
        
 
46
        /**
 
47
         * Right hand side of the assignment.
 
48
         */
 
49
        public Expression right {
 
50
                get { return _right; }
 
51
                set {
 
52
                        _right = value;
 
53
                        _right.parent_node = this;
 
54
                }
 
55
        }
 
56
        
 
57
        private Expression _left;
 
58
        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
        public Assignment (Expression left, Expression right, AssignmentOperator operator = AssignmentOperator.SIMPLE, SourceReference? source_reference = null) {
 
70
                this.right = right;
 
71
                this.operator = operator;
 
72
                this.source_reference = source_reference;
 
73
                this.left = left;
 
74
        }
 
75
        
 
76
        public override void accept (CodeVisitor visitor) {
 
77
                visitor.visit_assignment (this);
 
78
 
 
79
                visitor.visit_expression (this);
 
80
        }
 
81
 
 
82
        public override void accept_children (CodeVisitor visitor) {
 
83
                left.accept (visitor);
 
84
                right.accept (visitor);
 
85
        }
 
86
 
 
87
        public override void replace_expression (Expression old_node, Expression new_node) {
 
88
                if (left == old_node) {
 
89
                        left = new_node;
 
90
                }
 
91
                if (right == old_node) {
 
92
                        right = new_node;
 
93
                }
 
94
        }
 
95
 
 
96
        public override bool is_pure () {
 
97
                return false;
 
98
        }
 
99
 
 
100
        public override bool check (CodeContext context) {
 
101
                if (checked) {
 
102
                        return !error;
 
103
                }
 
104
 
 
105
                checked = true;
 
106
 
 
107
                if (left is Tuple && operator == AssignmentOperator.SIMPLE && parent_node is ExpressionStatement) {
 
108
                        var tuple = (Tuple) left;
 
109
 
 
110
                        var local = new LocalVariable (null, get_temp_name (), right, right.source_reference);
 
111
                        var decl = new DeclarationStatement (local, source_reference);
 
112
                        decl.check (context);
 
113
                        insert_statement (context.analyzer.insert_block, decl);
 
114
 
 
115
                        int i = 0;
 
116
                        ExpressionStatement stmt = null;
 
117
                        foreach (var expr in tuple.get_expressions ()) {
 
118
                                if (stmt != null) {
 
119
                                        stmt.check (context);
 
120
                                        insert_statement (context.analyzer.insert_block, stmt);
 
121
                                }
 
122
 
 
123
                                var temp_access = new MemberAccess.simple (local.name, right.source_reference);
 
124
                                var ea = new ElementAccess (temp_access, expr.source_reference);
 
125
                                ea.append_index (new IntegerLiteral (i.to_string (), expr.source_reference));
 
126
                                var assign = new Assignment (expr, ea, operator, expr.source_reference);
 
127
                                stmt = new ExpressionStatement (assign, expr.source_reference);
 
128
 
 
129
                                i++;
 
130
                        }
 
131
 
 
132
                        context.analyzer.replaced_nodes.add (this);
 
133
                        parent_node.replace_expression (this, stmt.expression);
 
134
                        return stmt.expression.check (context);
 
135
                }
 
136
 
 
137
                left.lvalue = true;
 
138
 
 
139
                if (!left.check (context)) {
 
140
                        // skip on error in inner expression
 
141
                        error = true;
 
142
                        return false;
 
143
                }
 
144
 
 
145
                if (left is MemberAccess) {
 
146
                        var ma = (MemberAccess) left;
 
147
 
 
148
                        if ((!(ma.symbol_reference is Signal || ma.symbol_reference is DynamicProperty) && ma.value_type == null) ||
 
149
                            (ma.inner == null && ma.member_name == "this" && context.analyzer.is_in_instance_method ())) {
 
150
                                error = true;
 
151
                                Report.error (source_reference, "unsupported lvalue in assignment");
 
152
                                return false;
 
153
                        }
 
154
                        if (ma.prototype_access) {
 
155
                                error = true;
 
156
                                Report.error (source_reference, "Access to instance member `%s' denied".printf (ma.symbol_reference.get_full_name ()));
 
157
                                return false;
 
158
                        }
 
159
 
 
160
                        if (ma.error || ma.symbol_reference == null) {
 
161
                                error = true;
 
162
                                /* if no symbol found, skip this check */
 
163
                                return false;
 
164
                        }
 
165
 
 
166
                        if (ma.symbol_reference is DynamicSignal) {
 
167
                                // target_type not available for dynamic signals
 
168
                                if (!context.deprecated) {
 
169
                                        Report.warning (source_reference, "deprecated syntax, use `connect' method instead");
 
170
                                }
 
171
                        } else if (ma.symbol_reference is Signal) {
 
172
                                if (!context.deprecated) {
 
173
                                        Report.warning (source_reference, "deprecated syntax, use `connect' method instead");
 
174
                                }
 
175
                                var sig = (Signal) ma.symbol_reference;
 
176
                                right.target_type = new DelegateType (sig.get_delegate (ma.inner.value_type, this));
 
177
                        } else {
 
178
                                right.formal_target_type = ma.formal_value_type;
 
179
                                right.target_type = ma.value_type;
 
180
                        }
 
181
                } else if (left is ElementAccess) {
 
182
                        var ea = (ElementAccess) left;
 
183
 
 
184
                        if (ea.container.value_type.data_type == context.analyzer.string_type.data_type) {
 
185
                                error = true;
 
186
                                Report.error (ea.source_reference, "strings are immutable");
 
187
                                return false;
 
188
                        } else if (ea.container is MemberAccess && ea.container.symbol_reference is Signal) {
 
189
                                var ma = (MemberAccess) ea.container;
 
190
                                var sig = (Signal) ea.container.symbol_reference;
 
191
                                right.target_type = new DelegateType (sig.get_delegate (ma.inner.value_type, this));
 
192
                        } else if (ea.container.value_type.get_member ("set") is Method) {
 
193
                                var set_call = new MethodCall (new MemberAccess (ea.container, "set", source_reference), source_reference);
 
194
                                foreach (Expression e in ea.get_indices ()) {
 
195
                                        set_call.add_argument (e);
 
196
                                }
 
197
                                set_call.add_argument (right);
 
198
                                parent_node.replace_expression (this, set_call);
 
199
                                return set_call.check (context);
 
200
                        } else {
 
201
                                right.target_type = left.value_type;
 
202
                        }
 
203
                } else if (left is PointerIndirection) {
 
204
                        right.target_type = left.value_type;
 
205
                } else {
 
206
                        error = true;
 
207
                        Report.error (source_reference, "unsupported lvalue in assignment");
 
208
                        return false;
 
209
                }
 
210
 
 
211
                if (!right.check (context)) {
 
212
                        // skip on error in inner expression
 
213
                        error = true;
 
214
                        return false;
 
215
                }
 
216
 
 
217
                if (operator != AssignmentOperator.SIMPLE && left is MemberAccess) {
 
218
                        // transform into simple assignment
 
219
                        // FIXME: only do this if the backend doesn't support
 
220
                        // the assignment natively
 
221
 
 
222
                        var ma = (MemberAccess) left;
 
223
 
 
224
                        if (!(ma.symbol_reference is Signal)) {
 
225
                                var old_value = new MemberAccess (ma.inner, ma.member_name);
 
226
 
 
227
                                var bin = new BinaryExpression (BinaryOperator.PLUS, old_value, right, source_reference);
 
228
                                bin.target_type = right.target_type;
 
229
                                right.target_type = right.target_type.copy ();
 
230
                                right.target_type.value_owned = false;
 
231
 
 
232
                                if (operator == AssignmentOperator.BITWISE_OR) {
 
233
                                        bin.operator = BinaryOperator.BITWISE_OR;
 
234
                                } else if (operator == AssignmentOperator.BITWISE_AND) {
 
235
                                        bin.operator = BinaryOperator.BITWISE_AND;
 
236
                                } else if (operator == AssignmentOperator.BITWISE_XOR) {
 
237
                                        bin.operator = BinaryOperator.BITWISE_XOR;
 
238
                                } else if (operator == AssignmentOperator.ADD) {
 
239
                                        bin.operator = BinaryOperator.PLUS;
 
240
                                } else if (operator == AssignmentOperator.SUB) {
 
241
                                        bin.operator = BinaryOperator.MINUS;
 
242
                                } else if (operator == AssignmentOperator.MUL) {
 
243
                                        bin.operator = BinaryOperator.MUL;
 
244
                                } else if (operator == AssignmentOperator.DIV) {
 
245
                                        bin.operator = BinaryOperator.DIV;
 
246
                                } else if (operator == AssignmentOperator.PERCENT) {
 
247
                                        bin.operator = BinaryOperator.MOD;
 
248
                                } else if (operator == AssignmentOperator.SHIFT_LEFT) {
 
249
                                        bin.operator = BinaryOperator.SHIFT_LEFT;
 
250
                                } else if (operator == AssignmentOperator.SHIFT_RIGHT) {
 
251
                                        bin.operator = BinaryOperator.SHIFT_RIGHT;
 
252
                                }
 
253
 
 
254
                                right = bin;
 
255
                                right.check (context);
 
256
 
 
257
                                operator = AssignmentOperator.SIMPLE;
 
258
                        }
 
259
                }
 
260
 
 
261
                if (left.symbol_reference is Signal) {
 
262
                        var sig = (Signal) left.symbol_reference;
 
263
 
 
264
                        var m = right.symbol_reference as Method;
 
265
 
 
266
                        if (m == null) {
 
267
                                error = true;
 
268
                                Report.error (right.source_reference, "unsupported expression for signal handler");
 
269
                                return false;
 
270
                        }
 
271
 
 
272
                        var dynamic_sig = sig as DynamicSignal;
 
273
                        var right_ma = right as MemberAccess;
 
274
                        if (dynamic_sig != null) {
 
275
                                bool first = true;
 
276
                                foreach (Parameter param in dynamic_sig.handler.value_type.get_parameters ()) {
 
277
                                        if (first) {
 
278
                                                // skip sender parameter
 
279
                                                first = false;
 
280
                                        } else {
 
281
                                                dynamic_sig.add_parameter (param.copy ());
 
282
                                        }
 
283
                                }
 
284
                                right.target_type = new DelegateType (sig.get_delegate (new ObjectType ((ObjectTypeSymbol) sig.parent_symbol), this));
 
285
                        } else if (!right.value_type.compatible (right.target_type)) {
 
286
                                var delegate_type = (DelegateType) right.target_type;
 
287
 
 
288
                                error = true;
 
289
                                Report.error (right.source_reference, "method `%s' is incompatible with signal `%s', expected `%s'".printf (right.value_type.to_string (), right.target_type.to_string (), delegate_type.delegate_symbol.get_prototype_string (m.name)));
 
290
                                return false;
 
291
                        } else if (right_ma != null && right_ma.prototype_access) {
 
292
                                error = true;
 
293
                                Report.error (right.source_reference, "Access to instance member `%s' denied".printf (m.get_full_name ()));
 
294
                                return false;
 
295
                        }
 
296
                } else if (left is MemberAccess) {
 
297
                        var ma = (MemberAccess) left;
 
298
 
 
299
                        if (ma.symbol_reference is Property) {
 
300
                                var prop = (Property) ma.symbol_reference;
 
301
 
 
302
                                var dynamic_prop = prop as DynamicProperty;
 
303
                                if (dynamic_prop != null) {
 
304
                                        dynamic_prop.property_type = right.value_type.copy ();
 
305
                                        left.value_type = dynamic_prop.property_type.copy ();
 
306
                                }
 
307
 
 
308
                                if (prop.set_accessor == null
 
309
                                    || (!prop.set_accessor.writable && !(context.analyzer.find_current_method () is CreationMethod || context.analyzer.is_in_constructor ()))) {
 
310
                                        ma.error = true;
 
311
                                        Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
 
312
                                        return false;
 
313
                                } else if (!context.deprecated
 
314
                                           && !prop.set_accessor.writable
 
315
                                           && context.analyzer.find_current_method () is CreationMethod) {
 
316
                                        if (ma.inner.symbol_reference != context.analyzer.find_current_method ().this_parameter) {
 
317
                                                // trying to set construct-only property in creation method for foreign instance
 
318
                                                Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
 
319
                                                return false;
 
320
                                        } else {
 
321
                                                Report.error (ma.source_reference, "Cannot assign to construct-only properties, use Object (property: value) constructor chain up");
 
322
                                                return false;
 
323
                                        }
 
324
                                }
 
325
                        } else if (ma.symbol_reference is Variable && right.value_type == null) {
 
326
                                var variable = (Variable) ma.symbol_reference;
 
327
 
 
328
                                if (right.symbol_reference is Method &&
 
329
                                    variable.variable_type is DelegateType) {
 
330
                                        var m = (Method) right.symbol_reference;
 
331
                                        var dt = (DelegateType) variable.variable_type;
 
332
                                        var cb = dt.delegate_symbol;
 
333
 
 
334
                                        /* check whether method matches callback type */
 
335
                                        if (!cb.matches_method (m, dt)) {
 
336
                                                error = true;
 
337
                                                Report.error (source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
 
338
                                                return false;
 
339
                                        }
 
340
 
 
341
                                        right.value_type = variable.variable_type;
 
342
                                } else {
 
343
                                        error = true;
 
344
                                        Report.error (source_reference, "Assignment: Invalid assignment attempt");
 
345
                                        return false;
 
346
                                }
 
347
                        }
 
348
 
 
349
                        if (left.value_type != null && right.value_type != null) {
 
350
                                /* if there was an error on either side,
 
351
                                 * i.e. {left|right}.value_type == null, skip type check */
 
352
 
 
353
                                if (!right.value_type.compatible (left.value_type)) {
 
354
                                        error = true;
 
355
                                        Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (right.value_type.to_string (), left.value_type.to_string ()));
 
356
                                        return false;
 
357
                                }
 
358
 
 
359
                                if (!(ma.symbol_reference is Property)) {
 
360
                                        if (right.value_type.is_disposable ()) {
 
361
                                                /* rhs transfers ownership of the expression */
 
362
                                                if (!(left.value_type is PointerType) && !left.value_type.value_owned) {
 
363
                                                        /* lhs doesn't own the value */
 
364
                                                        error = true;
 
365
                                                        Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
 
366
                                                }
 
367
                                        } else if (left.value_type.value_owned) {
 
368
                                                /* lhs wants to own the value
 
369
                                                 * rhs doesn't transfer the ownership
 
370
                                                 * code generator needs to add reference
 
371
                                                 * increment calls */
 
372
                                        }
 
373
                                }
 
374
                        }
 
375
 
 
376
                        var right_ma = right as MemberAccess;
 
377
                        if (right_ma != null && ma.symbol_reference == right_ma.symbol_reference) {
 
378
                                if (ma.symbol_reference is LocalVariable || ma.symbol_reference is Parameter) {
 
379
                                        Report.warning (source_reference, "Assignment to same variable");
 
380
                                } else if (ma.symbol_reference is Field) {
 
381
                                        var f = (Field) ma.symbol_reference;
 
382
                                        if (f.binding == MemberBinding.STATIC) {
 
383
                                                Report.warning (source_reference, "Assignment to same variable");
 
384
                                        } else {
 
385
                                                var ma_inner = ma.inner as MemberAccess;
 
386
                                                var right_ma_inner = right_ma.inner as MemberAccess;
 
387
                                                if (ma_inner != null && ma_inner.member_name == "this" && ma_inner.inner == null &&
 
388
                                                    right_ma_inner != null && right_ma_inner.member_name == "this" && right_ma_inner.inner == null) {
 
389
                                                        Report.warning (source_reference, "Assignment to same variable");
 
390
                                                }
 
391
                                        }
 
392
                                }
 
393
                        }
 
394
                } else if (left is ElementAccess) {
 
395
                        var ea = (ElementAccess) left;
 
396
 
 
397
                        if (!right.value_type.compatible (left.value_type)) {
 
398
                                error = true;
 
399
                                Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (right.value_type.to_string (), left.value_type.to_string ()));
 
400
                                return false;
 
401
                        }
 
402
 
 
403
                        if (right.value_type.is_disposable ()) {
 
404
                                /* rhs transfers ownership of the expression */
 
405
 
 
406
                                DataType element_type;
 
407
 
 
408
                                if (ea.container.value_type is ArrayType) {
 
409
                                        var array_type = (ArrayType) ea.container.value_type;
 
410
                                        element_type = array_type.element_type;
 
411
                                } else {
 
412
                                        var args = ea.container.value_type.get_type_arguments ();
 
413
                                        assert (args.size == 1);
 
414
                                        element_type = args.get (0);
 
415
                                }
 
416
 
 
417
                                if (!(element_type is PointerType) && !element_type.value_owned) {
 
418
                                        /* lhs doesn't own the value */
 
419
                                        error = true;
 
420
                                        Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
 
421
                                        return false;
 
422
                                }
 
423
                        } else if (left.value_type.value_owned) {
 
424
                                /* lhs wants to own the value
 
425
                                 * rhs doesn't transfer the ownership
 
426
                                 * code generator needs to add reference
 
427
                                 * increment calls */
 
428
                        }
 
429
                } else {
 
430
                        return true;
 
431
                }
 
432
 
 
433
                if (left.value_type != null) {
 
434
                        value_type = left.value_type.copy ();
 
435
                        value_type.value_owned = false;
 
436
                } else {
 
437
                        value_type = null;
 
438
                }
 
439
 
 
440
                add_error_types (left.get_error_types ());
 
441
                add_error_types (right.get_error_types ());
 
442
 
 
443
                return !error;
 
444
        }
 
445
 
 
446
        bool is_array_add () {
 
447
                var binary = right as BinaryExpression;
 
448
                if (binary != null && binary.left.value_type is ArrayType) {
 
449
                        if (binary.operator == BinaryOperator.PLUS) {
 
450
                                if (left.symbol_reference == binary.left.symbol_reference) {
 
451
                                        return true;
 
452
                                }
 
453
                        }
 
454
                }
 
455
 
 
456
                return false;
 
457
        }
 
458
 
 
459
        public override void emit (CodeGenerator codegen) {
 
460
                var ma = left as MemberAccess;
 
461
                var ea = left as ElementAccess;
 
462
                var pi = left as PointerIndirection;
 
463
                if (ma != null) {
 
464
                        var local = ma.symbol_reference as LocalVariable;
 
465
                        var param = ma.symbol_reference as Parameter;
 
466
                        var field = ma.symbol_reference as Field;
 
467
                        var property = ma.symbol_reference as Property;
 
468
 
 
469
                        bool instance = (field != null && field.binding != MemberBinding.STATIC)
 
470
                                || (property != null && property.binding != MemberBinding.STATIC);
 
471
 
 
472
                        if (operator == AssignmentOperator.SIMPLE &&
 
473
                            (local != null || param != null || field != null) &&
 
474
                            !is_array_add () &&
 
475
                            !(field is ArrayLengthField) &&
 
476
                                !(left.value_type.is_real_non_null_struct_type () && right is ObjectCreationExpression)) {
 
477
                                // visit_assignment not necessary
 
478
                                if (instance && ma.inner != null) {
 
479
                                        ma.inner.emit (codegen);
 
480
                                }
 
481
 
 
482
                                right.emit (codegen);
 
483
                                var new_value = right.target_value;
 
484
 
 
485
                                if (local != null) {
 
486
                                        codegen.store_local (local, new_value, false);
 
487
                                } else if (param != null) {
 
488
                                        codegen.store_parameter (param, new_value);
 
489
                                } else if (field != null) {
 
490
                                        codegen.store_field (field, instance && ma.inner != null ? ma.inner.target_value : null, new_value);
 
491
                                }
 
492
 
 
493
                                if (!(parent_node is ExpressionStatement)) {
 
494
                                        // when load_variable is changed to use temporary
 
495
                                        // variables, replace following code with this line
 
496
                                        // target_value = new_value;
 
497
                                        if (local != null) {
 
498
                                                target_value = codegen.load_local (local);
 
499
                                        } else if (param != null) {
 
500
                                                target_value = codegen.load_parameter (param);
 
501
                                        } else if (field != null) {
 
502
                                                target_value = codegen.load_field (field, instance && ma.inner != null ? ma.inner.target_value : null);
 
503
                                        }
 
504
                                }
 
505
 
 
506
                                codegen.visit_expression (this);
 
507
                                return;
 
508
                        }
 
509
 
 
510
                        if (instance && ma.inner != null && property != null) {
 
511
                                ma.inner.emit (codegen);
 
512
                        } else {
 
513
                                // always process full lvalue
 
514
                                // current codegen depends on it
 
515
                                // should be removed when moving codegen from
 
516
                                // visit_assignment to emit_store_field/local/param
 
517
                                ma.emit (codegen);
 
518
                        }
 
519
                } else if (ea != null) {
 
520
                        // always process full lvalue
 
521
                        // current codegen depends on it
 
522
                        // should be removed when moving codegen from
 
523
                        // visit_assignment to emit_store_element
 
524
                        ea.emit (codegen);
 
525
                } else if (pi != null) {
 
526
                        // always process full lvalue
 
527
                        // current codegen depends on it
 
528
                        // should be removed when moving codegen from
 
529
                        // visit_assignment to emit_store_indirectZ
 
530
                        pi.emit (codegen);
 
531
                }
 
532
 
 
533
                right.emit (codegen);
 
534
 
 
535
                codegen.visit_assignment (this);
 
536
 
 
537
                codegen.visit_expression (this);
 
538
        }
 
539
 
 
540
        public override void get_defined_variables (Collection<Variable> collection) {
 
541
                right.get_defined_variables (collection);
 
542
                left.get_defined_variables (collection);
 
543
                var local = left.symbol_reference as LocalVariable;
 
544
                var param = left.symbol_reference as Parameter;
 
545
                if (local != null) {
 
546
                        collection.add (local);
 
547
                } else if (param != null && param.direction == ParameterDirection.OUT) {
 
548
                        collection.add (param);
 
549
                }
 
550
        }
 
551
 
 
552
        public override void get_used_variables (Collection<Variable> collection) {
 
553
                var ma = left as MemberAccess;
 
554
                var ea = left as ElementAccess;
 
555
                if (ma != null && ma.inner != null) {
 
556
                        ma.inner.get_used_variables (collection);
 
557
                } else if (ea != null) {
 
558
                        ea.get_used_variables (collection);
 
559
                }
 
560
                right.get_used_variables (collection);
 
561
        }
 
562
}
 
563
        
 
564
public enum Vala.AssignmentOperator {
 
565
        NONE,
 
566
        SIMPLE,
 
567
        BITWISE_OR,
 
568
        BITWISE_AND,
 
569
        BITWISE_XOR,
 
570
        ADD,
 
571
        SUB,
 
572
        MUL,
 
573
        DIV,
 
574
        PERCENT,
 
575
        SHIFT_LEFT,
 
576
        SHIFT_RIGHT
 
577
}