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

            Line data    Source code
       1              : /* valalambdaexpression.vala
       2              :  *
       3              :  * Copyright (C) 2006-2010  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              : using GLib;
      24              : 
      25              : /**
      26              :  * Represents a lambda expression in the source code.
      27              :  *
      28              :  * Lambda expressions are anonymous methods with implicitly typed parameters.
      29              :  */
      30        14493 : public class Vala.LambdaExpression : Expression {
      31              :         /**
      32              :          * The expression body of this lambda expression. Only one of
      33              :          * expression_body or statement_body may be set.
      34              :          */
      35              :         public Expression expression_body {
      36        32547 :                 get { return _expression_body; }
      37         1552 :                 private set {
      38        36343 :                         _expression_body = value;
      39         1552 :                         if (_expression_body != null) {
      40         1552 :                                 _expression_body.parent_node = this;
      41              :                         }
      42              :                 }
      43              :         }
      44              : 
      45              :         /**
      46              :          * The statement body of this lambda expression. Only one of
      47              :          * expression_body or statement_body may be set.
      48              :          */
      49              :         public Block statement_body {
      50        29020 :                 get { return _statement_body; }
      51         4930 :                 private set {
      52         9860 :                         _statement_body = value;
      53         4930 :                         if (_statement_body != null) {
      54         4930 :                                 _statement_body.parent_node = this;
      55              :                         }
      56              :                 }
      57              :         }
      58              : 
      59              :         /**
      60              :          * The generated method.
      61              :          */
      62        35140 :         public Method method { get; private set; }
      63              : 
      64        12964 :         private List<Parameter> parameters = new ArrayList<Parameter> ();
      65         6482 :         Block _statement_body;
      66         6482 :         Expression _expression_body;
      67              : 
      68              :         /**
      69              :          * Creates a new lambda expression.
      70              :          *
      71              :          * @param expression_body  expression body
      72              :          * @param source_reference reference to source code
      73              :          * @return                 newly created lambda expression
      74              :          */
      75         4656 :         public LambdaExpression (Expression expression_body, SourceReference? source_reference = null) {
      76         1552 :                 this.source_reference = source_reference;
      77         1552 :                 this.expression_body = expression_body;
      78              :         }
      79              : 
      80              :         /**
      81              :          * Creates a new lambda expression with statement body.
      82              :          *
      83              :          * @param statement_body   statement body
      84              :          * @param source_reference reference to source code
      85              :          * @return                 newly created lambda expression
      86              :          */
      87        14790 :         public LambdaExpression.with_statement_body (Block statement_body, SourceReference? source_reference = null) {
      88         4930 :                 this.statement_body = statement_body;
      89         4930 :                 this.source_reference = source_reference;
      90              :         }
      91              : 
      92              :         /**
      93              :          * Appends implicitly typed parameter.
      94              :          *
      95              :          * @param param parameter name
      96              :          */
      97        12410 :         public void add_parameter (Parameter param) {
      98        12410 :                 parameters.add (param);
      99              :         }
     100              : 
     101              :         /**
     102              :          * Returns the parameter list.
     103              :          *
     104              :          * @return parameter list
     105              :          */
     106         6020 :         public unowned List<Parameter> get_parameters () {
     107         6020 :                 return parameters;
     108              :         }
     109              : 
     110        21018 :         public override void accept (CodeVisitor visitor) {
     111        21018 :                 visitor.visit_lambda_expression (this);
     112              : 
     113        21018 :                 visitor.visit_expression (this);
     114              :         }
     115              : 
     116        21371 :         public override void accept_children (CodeVisitor visitor) {
     117        21371 :                 if (method == null) {
     118        16509 :                         if (expression_body != null) {
     119         4290 :                                 expression_body.accept (visitor);
     120         4290 :                                 visitor.visit_end_full_expression (expression_body);
     121        12219 :                         } else if (statement_body != null) {
     122        12219 :                                 statement_body.accept (visitor);
     123              :                         }
     124              :                 } else {
     125         4862 :                         method.accept (visitor);
     126              :                 }
     127              :         }
     128              : 
     129            0 :         public override bool is_pure () {
     130            0 :                 return false;
     131              :         }
     132              : 
     133         6021 :         public override bool check (CodeContext context) {
     134         6021 :                 if (checked) {
     135            0 :                         return !error;
     136              :                 }
     137              : 
     138         6021 :                 checked = true;
     139              : 
     140         6021 :                 if (!(target_type is DelegateType)) {
     141            1 :                         error = true;
     142            1 :                         if (target_type != null) {
     143            1 :                                 Report.error (source_reference, "Cannot convert lambda expression to `%s'", target_type.to_string ());
     144              :                         } else {
     145            0 :                                 Report.error (source_reference, "lambda expression not allowed in this context");
     146              :                         }
     147            1 :                         return false;
     148              :                 }
     149              : 
     150         6020 :                 var cb = (Delegate) ((DelegateType) target_type).delegate_symbol;
     151         6020 :                 var return_type = cb.return_type.get_actual_type (target_type, null, this);
     152         6020 :                 method = new Method ("@lambda", return_type, source_reference);
     153              :                 // track usage for flow analyzer
     154         6020 :                 method.used = true;
     155              : 
     156         6020 :                 if (return_type is ArrayType) {
     157            2 :                         method.copy_attribute_bool (cb, "CCode", "array_length");
     158            2 :                         method.copy_attribute_bool (cb, "CCode", "array_null_terminated");
     159            2 :                         method.copy_attribute_string (cb, "CCode", "array_length_type");
     160         6018 :                 } else if (return_type is DelegateType) {
     161            1 :                         method.copy_attribute_bool (cb, "CCode", "delegate_target");
     162              :                 }
     163              : 
     164        10474 :                 if (!cb.has_target || !context.analyzer.is_in_instance_method ()) {
     165         1566 :                         method.binding = MemberBinding.STATIC;
     166              :                 } else {
     167         4454 :                         var sym = context.analyzer.current_symbol;
     168        13367 :                         while (method.this_parameter == null) {
     169         8914 :                                 if (sym is Property) {
     170            1 :                                         var prop = (Property) sym;
     171            1 :                                         method.this_parameter = prop.this_parameter;
     172         8913 :                                 } else if (sym is Constructor) {
     173            1 :                                         var c = (Constructor) sym;
     174            1 :                                         method.this_parameter = c.this_parameter;
     175         8912 :                                 } else if (sym is Destructor) {
     176            1 :                                         var d = (Destructor) sym;
     177            1 :                                         method.this_parameter = d.this_parameter;
     178        13361 :                                 } else if (sym is Method) {
     179         4451 :                                         var m = (Method) sym;
     180         4451 :                                         method.this_parameter = m.this_parameter;
     181              :                                 }
     182              : 
     183        17826 :                                 sym = sym.parent_symbol;
     184              :                         }
     185              :                 }
     186         6020 :                 method.owner = context.analyzer.current_symbol.scope;
     187         6020 :                 method.parent_node = this;
     188              : 
     189         6020 :                 var lambda_params = get_parameters ();
     190         6020 :                 Iterator<Parameter> lambda_param_it = lambda_params.iterator ();
     191              : 
     192         6025 :                 if (cb.sender_type != null && lambda_params.size == cb.get_parameters ().size + 1) {
     193              :                         // lambda expression has sender parameter
     194            5 :                         lambda_param_it.next ();
     195              : 
     196            5 :                         Parameter lambda_param = lambda_param_it.get ();
     197            5 :                         lambda_param.variable_type = cb.sender_type;
     198            5 :                         method.add_parameter (lambda_param);
     199              :                 }
     200              : 
     201        29000 :                 foreach (Parameter cb_param in cb.get_parameters ()) {
     202        11509 :                         if (!lambda_param_it.next ()) {
     203              :                                 /* lambda expressions are allowed to have less parameters */
     204           19 :                                 break;
     205              :                         }
     206              : 
     207        11490 :                         Parameter lambda_param = lambda_param_it.get ();
     208              : 
     209        11490 :                         if (lambda_param.direction != cb_param.direction) {
     210            0 :                                 error = true;
     211            0 :                                 Report.error (lambda_param.source_reference, "direction of parameter `%s' is incompatible with the target delegate", lambda_param.name);
     212              :                         }
     213              : 
     214        11490 :                         lambda_param.variable_type = cb_param.variable_type.get_actual_type (target_type, null, this);
     215        11490 :                         lambda_param.base_parameter = cb_param;
     216        11490 :                         method.add_parameter (lambda_param);
     217              :                 }
     218              : 
     219         6020 :                 if (lambda_param_it.next ()) {
     220              :                         /* lambda expressions may not expect more parameters */
     221            0 :                         error = true;
     222            0 :                         Report.error (source_reference, "lambda expression: too many parameters");
     223            0 :                         return false;
     224              :                 }
     225              : 
     226         6020 :                 var error_types = new ArrayList<DataType> ();
     227         6020 :                 cb.get_error_types (error_types);
     228         6288 :                 foreach (var error_type in error_types) {
     229          134 :                         method.add_error_type (error_type.copy ());
     230              :                 }
     231              : 
     232         7458 :                 if (expression_body != null) {
     233         1438 :                         var block = new Block (source_reference);
     234         1438 :                         block.scope.parent_scope = method.scope;
     235              : 
     236         1438 :                         if (method.return_type.type_symbol != null) {
     237           17 :                                 block.add_statement (new ReturnStatement (expression_body, source_reference));
     238              :                         } else {
     239         1421 :                                 block.add_statement (new ExpressionStatement (expression_body, source_reference));
     240              :                         }
     241              : 
     242         1438 :                         method.body = block;
     243              :                 } else {
     244         4582 :                         method.body = statement_body;
     245              :                 }
     246         6020 :                 method.body.owner = method.scope;
     247              : 
     248              :                 // support use of generics in closures
     249         6020 :                 unowned Method? m = SemanticAnalyzer.find_parent_method (context.analyzer.current_symbol);
     250         6020 :                 if (m != null) {
     251         8853 :                         foreach (var type_param in m.get_type_parameters ()) {
     252         1418 :                                 method.add_type_parameter (new TypeParameter (type_param.name, type_param.source_reference));
     253              : 
     254         1418 :                                 method.closure = true;
     255         1418 :                                 m.body.captured = true;
     256              :                         }
     257              :                 }
     258              : 
     259              :                 /* lambda expressions should be usable like MemberAccess of a method */
     260         6020 :                 symbol_reference = method;
     261              : 
     262         6020 :                 method.check (context);
     263              : 
     264         6020 :                 value_type = new MethodType (method, source_reference);
     265         6020 :                 value_type.value_owned = target_type.value_owned;
     266              : 
     267         6020 :                 return !error;
     268              :         }
     269              : 
     270          353 :         public override void emit (CodeGenerator codegen) {
     271          353 :                 codegen.visit_lambda_expression (this);
     272              : 
     273          353 :                 codegen.visit_expression (this);
     274              :         }
     275              : 
     276         4202 :         public override void get_used_variables (Collection<Variable> collection) {
     277              :                 // require captured variables to be initialized
     278         4202 :                 if (method != null && method.closure) {
     279         3944 :                         method.get_captured_variables ((Collection<LocalVariable>) collection);
     280              :                 }
     281              :         }
     282              : }
        

Generated by: LCOV version 2.0-1