LCOV - code coverage report
Current view: top level - vala - valaunaryexpression.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 81.7 % 142 116
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valaunaryexpression.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 expression with one operand in the source code.
      26              :  *
      27              :  * Supports +, -, !, ~, ref, out.
      28              :  */
      29        41995 : public class Vala.UnaryExpression : Expression {
      30              :         /**
      31              :          * The unary operator.
      32              :          */
      33       305824 :         public UnaryOperator operator { get; private set; }
      34              : 
      35              :         /**
      36              :          * The operand.
      37              :          */
      38              :         public Expression inner {
      39       816881 :                 get {
      40       816881 :                         return _inner;
      41              :                 }
      42        42003 :                 private set {
      43        42003 :                         _inner = value;
      44        42003 :                         _inner.parent_node = this;
      45              :                 }
      46              :         }
      47              : 
      48        40458 :         private Expression _inner;
      49              : 
      50              :         /**
      51              :          * Creates a new unary expression.
      52              :          *
      53              :          * @param op     unary operator
      54              :          * @param _inner operand
      55              :          * @param source reference to source code
      56              :          * @return       newly created binary expression
      57              :          */
      58       121374 :         public UnaryExpression (UnaryOperator op, Expression _inner, SourceReference? source = null) {
      59        40458 :                 operator = op;
      60        40458 :                 inner = _inner;
      61        40458 :                 source_reference = source;
      62              :         }
      63              : 
      64       138571 :         public override void accept (CodeVisitor visitor) {
      65       138571 :                 visitor.visit_unary_expression (this);
      66              : 
      67       138571 :                 visitor.visit_expression (this);
      68              :         }
      69              : 
      70       137584 :         public override void accept_children (CodeVisitor visitor) {
      71       137584 :                 inner.accept (visitor);
      72              :         }
      73              : 
      74         1545 :         public override void replace_expression (Expression old_node, Expression new_node) {
      75         1545 :                 if (inner == old_node) {
      76         1545 :                         inner = new_node;
      77              :                 }
      78              :         }
      79              : 
      80            0 :         public override string to_string () {
      81            0 :                 return operator.to_string () + _inner.to_string ();
      82              :         }
      83              : 
      84          108 :         public override bool is_constant () {
      85          108 :                 if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
      86            0 :                         return false;
      87              :                 }
      88              : 
      89          108 :                 if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) {
      90          107 :                         unowned Field? field = inner.symbol_reference as Field;
      91          107 :                         if (field != null && field.binding == MemberBinding.STATIC) {
      92          108 :                                 return true;
      93              :                         } else {
      94            0 :                                 return false;
      95              :                         }
      96              :                 }
      97              : 
      98            1 :                 return inner.is_constant ();
      99              :         }
     100              : 
     101            0 :         public override bool is_pure () {
     102            0 :                 if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
     103            0 :                         return false;
     104              :                 }
     105              : 
     106            0 :                 return inner.is_pure ();
     107              :         }
     108              : 
     109          108 :         public override bool is_accessible (Symbol sym) {
     110          108 :                 return inner.is_accessible (sym);
     111              :         }
     112              : 
     113          456 :         bool is_numeric_type (DataType type) {
     114          456 :                 unowned Struct? st = type.type_symbol as Struct;
     115          456 :                 if (type.nullable || st == null) {
     116              :                         return false;
     117              :                 }
     118              : 
     119          455 :                 return st.is_integer_type () || st.is_floating_type ();
     120              :         }
     121              : 
     122          498 :         bool is_integer_type (DataType type) {
     123          498 :                 unowned Struct? st = type.type_symbol as Struct;
     124          498 :                 if (type.nullable || st == null) {
     125            2 :                         return false;
     126              :                 }
     127              : 
     128          496 :                 return st.is_integer_type ();
     129              :         }
     130              : 
     131       105761 :         public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
     132       105761 :                 inner.get_error_types (collection, source_reference);
     133              :         }
     134              : 
     135        39459 :         public override bool check (CodeContext context) {
     136        39459 :                 if (checked) {
     137          484 :                         return !error;
     138              :                 }
     139              : 
     140        38975 :                 checked = true;
     141              : 
     142        38975 :                 if (operator == UnaryOperator.REF || operator == UnaryOperator.OUT) {
     143        18836 :                         inner.lvalue = true;
     144        18836 :                         inner.target_type = target_type;
     145        20139 :                 } else if (operator == UnaryOperator.INCREMENT || operator == UnaryOperator.DECREMENT) {
     146          495 :                         inner.lvalue = true;
     147              :                 }
     148              : 
     149        38975 :                 if (!inner.check (context)) {
     150              :                         /* if there was an error in the inner expression, skip type check */
     151            0 :                         error = true;
     152            0 :                         return false;
     153        38975 :                 } else if (inner.value_type == null) {
     154            0 :                         error = true;
     155            0 :                         Report.error (inner.source_reference, "Invalid inner operand");
     156            0 :                         return false;
     157              :                 }
     158              : 
     159        38975 :                 if (inner.value_type is FieldPrototype || inner.value_type is PropertyPrototype) {
     160            1 :                         error = true;
     161            1 :                         Report.error (inner.source_reference, "Access to instance member `%s' denied", inner.symbol_reference.get_full_name ());
     162            1 :                         return false;
     163              :                 }
     164              : 
     165        38974 :                 switch (operator) {
     166              :                 case UnaryOperator.PLUS:
     167              :                 case UnaryOperator.MINUS:
     168              :                         // integer or floating point type
     169          456 :                         if (!is_numeric_type (inner.value_type)) {
     170            1 :                                 error = true;
     171            1 :                                 Report.error (source_reference, "Operator not supported for `%s'", inner.value_type.to_string ());
     172            1 :                                 return false;
     173              :                         }
     174              : 
     175          455 :                         value_type = inner.value_type;
     176          455 :                         break;
     177              :                 case UnaryOperator.LOGICAL_NEGATION:
     178              :                         // boolean type
     179        19184 :                         if (inner.value_type.nullable || !inner.value_type.compatible (context.analyzer.bool_type)) {
     180            1 :                                 error = true;
     181            1 :                                 Report.error (source_reference, "Operator not supported for `%s'", inner.value_type.to_string ());
     182            1 :                                 return false;
     183              :                         }
     184              : 
     185        19183 :                         value_type = inner.value_type;
     186        19183 :                         break;
     187              :                 case UnaryOperator.BITWISE_COMPLEMENT:
     188              :                         // integer type
     189            3 :                         if (!is_integer_type (inner.value_type) && !(inner.value_type is EnumValueType)) {
     190            1 :                                 error = true;
     191            1 :                                 Report.error (source_reference, "Operator not supported for `%s'", inner.value_type.to_string ());
     192            1 :                                 return false;
     193              :                         }
     194              : 
     195            2 :                         value_type = inner.value_type;
     196            2 :                         break;
     197              :                 case UnaryOperator.INCREMENT:
     198              :                 case UnaryOperator.DECREMENT:
     199              :                         // integer type
     200          495 :                         if (!is_integer_type (inner.value_type)) {
     201            1 :                                 error = true;
     202            1 :                                 Report.error (source_reference, "Operator not supported for `%s'", inner.value_type.to_string ());
     203            1 :                                 return false;
     204              :                         }
     205              : 
     206          494 :                         if (!(inner is MemberAccess)) {
     207            1 :                                 error = true;
     208            1 :                                 Report.error (source_reference, "Prefix operators not supported for this expression");
     209            1 :                                 return false;
     210              :                         }
     211              : 
     212          493 :                         value_type = inner.value_type;
     213          493 :                         break;
     214              :                 case UnaryOperator.REF:
     215              :                 case UnaryOperator.OUT:
     216        18836 :                         unowned ElementAccess? ea = inner as ElementAccess;
     217        18836 :                         if (inner.symbol_reference is Field || inner.symbol_reference is Parameter || inner.symbol_reference is LocalVariable ||
     218            3 :                             (ea != null && ea.container.value_type is ArrayType)) {
     219              :                                 // ref and out can only be used with fields, parameters, local variables, and array element access
     220        18834 :                                 lvalue = true;
     221              :                                 // `ref foo` or `out foo` is used as synonym for `&foo`
     222        18834 :                                 if (parent_node is InitializerList || parent_node is MemberInitializer) {
     223          109 :                                         value_type = new PointerType (inner.value_type, inner.source_reference);
     224              :                                 } else {
     225        18725 :                                         value_type = inner.value_type;
     226              :                                 }
     227              :                         } else {
     228            2 :                                 error = true;
     229            2 :                                 Report.error (source_reference, "ref and out method arguments can only be used with fields, parameters, local variables, and array element access");
     230            2 :                                 return false;
     231              :                         }
     232        18834 :                         if (inner.symbol_reference != null && inner.symbol_reference.has_attribute ("GtkChild")) {
     233            2 :                                 error = true;
     234            2 :                                 Report.error (source_reference, "Assignment of [GtkChild] `%s' is not allowed", inner.symbol_reference.get_full_name ());
     235            2 :                                 return false;
     236              :                         }
     237              :                         break;
     238              :                 default:
     239            0 :                         error = true;
     240            0 :                         Report.error (source_reference, "internal error: unsupported unary operator");
     241            0 :                         return false;
     242              :                 }
     243              : 
     244        38965 :                 value_type.check (context);
     245              : 
     246        38965 :                 return !error;
     247              :         }
     248              : 
     249         3684 :         public override void emit (CodeGenerator codegen) {
     250         3684 :                 inner.emit (codegen);
     251              : 
     252         3684 :                 codegen.visit_unary_expression (this);
     253              : 
     254         3684 :                 codegen.visit_expression (this);
     255              :         }
     256              : 
     257        82638 :         public override void get_defined_variables (Collection<Variable> collection) {
     258        82638 :                 inner.get_defined_variables (collection);
     259        82638 :                 if (operator == UnaryOperator.OUT || operator == UnaryOperator.REF) {
     260        38523 :                         unowned LocalVariable? local = inner.symbol_reference as LocalVariable;
     261        38523 :                         unowned Parameter? param = inner.symbol_reference as Parameter;
     262        38523 :                         if (local != null) {
     263        32631 :                                 collection.add (local);
     264              :                         }
     265        38523 :                         if (param != null && param.direction == ParameterDirection.OUT) {
     266           21 :                                 collection.add (param);
     267              :                         }
     268              :                 }
     269              :         }
     270              : 
     271        27548 :         public override void get_used_variables (Collection<Variable> collection) {
     272        27548 :                 if (operator != UnaryOperator.OUT) {
     273        16730 :                         inner.get_used_variables (collection);
     274              :                 }
     275              :         }
     276              : }
     277              : 
     278              : public enum Vala.UnaryOperator {
     279              :         NONE,
     280              :         PLUS,
     281              :         MINUS,
     282              :         LOGICAL_NEGATION,
     283              :         BITWISE_COMPLEMENT,
     284              :         INCREMENT,
     285              :         DECREMENT,
     286              :         REF,
     287              :         OUT;
     288              : 
     289              :         public unowned string to_string () {
     290            0 :                 switch (this) {
     291            0 :                 case PLUS: return "+";
     292            0 :                 case MINUS: return "-";
     293            0 :                 case LOGICAL_NEGATION: return "!";
     294            0 :                 case BITWISE_COMPLEMENT: return "~";
     295            0 :                 case INCREMENT: return "++";
     296            0 :                 case DECREMENT: return "--";
     297            0 :                 case REF: return "ref ";
     298            0 :                 case OUT: return "out ";
     299            0 :                 default: assert_not_reached ();
     300              :                 }
     301              :         }
     302              : 
     303              : }
        

Generated by: LCOV version 2.0-1