1 /* valalambdaexpression.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
27 * Represents a lambda expression in the source code. Lambda expressions are
28 * anonymous methods with implicitly typed parameters.
30 public class Vala
.LambdaExpression
: Expression
{
32 * The expression body of this lambda expression. Only one of
33 * expression_body or statement_body may be set.
35 public Expression expression_body
{ get; set; }
38 * The statement body of this lambda expression. Only one of
39 * expression_body or statement_body may be set.
41 public Block statement_body
{ get; set; }
44 * The generated method.
46 public Method method
{ get; set; }
48 private Gee
.List
<string> parameters
= new ArrayList
<string> ();
51 * Creates a new lambda expression.
53 * @param expression_body expression body
54 * @param source_reference reference to source code
55 * @return newly created lambda expression
57 public LambdaExpression (Expression expression_body
, SourceReference source_reference
) {
58 this
.source_reference
= source_reference
;
59 this
.expression_body
= expression_body
;
63 * Creates a new lambda expression with statement body.
65 * @param statement_body statement body
66 * @param source_reference reference to source code
67 * @return newly created lambda expression
69 public LambdaExpression
.with_statement_body (Block statement_body
, SourceReference source_reference
) {
70 this
.statement_body
= statement_body
;
71 this
.source_reference
= source_reference
;
75 * Appends implicitly typed parameter.
77 * @param param parameter name
79 public void add_parameter (string param
) {
80 parameters
.add (param
);
84 * Returns copy of parameter list.
86 * @return parameter list
88 public Gee
.List
<string> get_parameters () {
89 return new ReadOnlyList
<string> (parameters
);
92 public override void accept (CodeVisitor visitor
) {
93 visitor
.visit_lambda_expression (this
);
95 visitor
.visit_expression (this
);
98 public override void accept_children (CodeVisitor visitor
) {
100 if (expression_body
!= null) {
101 expression_body
.accept (visitor
);
102 visitor
.visit_end_full_expression (expression_body
);
103 } else if (statement_body
!= null) {
104 statement_body
.accept (visitor
);
107 method
.accept (visitor
);
111 public override bool is_pure () {
115 string get_lambda_name (SemanticAnalyzer analyzer
) {
116 var result
= "__lambda%d".printf (analyzer
.next_lambda_id
);
118 analyzer
.next_lambda_id
++;
123 public override bool check (SemanticAnalyzer analyzer
) {
130 if (!(target_type is DelegateType
)) {
132 Report
.error (source_reference
, "lambda expression not allowed in this context");
136 var cb
= (Delegate
) ((DelegateType
) target_type
).delegate_symbol
;
137 method
= new
Method (get_lambda_name (analyzer
), cb
.return_type
);
138 if (!cb
.has_target
|| !analyzer
.is_in_instance_method ()) {
139 method
.binding
= MemberBinding
.STATIC
;
141 var sym
= analyzer
.current_symbol
;
142 while (method
.this_parameter
== null) {
143 if (sym is Property
) {
144 var prop
= (Property
) sym
;
145 method
.this_parameter
= prop
.this_parameter
;
146 } else if (sym is Constructor
) {
147 var c
= (Constructor
) sym
;
148 method
.this_parameter
= c
.this_parameter
;
149 } else if (sym is Destructor
) {
150 var d
= (Destructor
) sym
;
151 method
.this_parameter
= d
.this_parameter
;
152 } else if (sym is Method
) {
153 var m
= (Method
) sym
;
154 method
.this_parameter
= m
.this_parameter
;
157 sym
= sym
.parent_symbol
;
160 method
.owner
= analyzer
.current_symbol
.scope
;
162 var lambda_params
= get_parameters ();
163 Iterator
<string> lambda_param_it
= lambda_params
.iterator ();
164 foreach (FormalParameter cb_param
in cb
.get_parameters ()) {
165 if (!lambda_param_it
.next ()) {
166 /* lambda expressions are allowed to have less parameters */
170 string lambda_param
= lambda_param_it
.get ();
172 var param
= new
FormalParameter (lambda_param
, cb_param
.parameter_type
);
174 method
.add_parameter (param
);
177 if (lambda_param_it
.next ()) {
178 /* lambda expressions may not expect more parameters */
180 Report
.error (source_reference
, "lambda expression: too many parameters");
184 foreach (var error_type
in cb
.get_error_types ()) {
185 method
.add_error_type (error_type
.copy ());
188 if (expression_body
!= null) {
189 var block
= new
Block (source_reference
);
190 block
.scope
.parent_scope
= method
.scope
;
192 if (method
.return_type
.data_type
!= null) {
193 block
.add_statement (new
ReturnStatement (expression_body
, source_reference
));
195 block
.add_statement (new
ExpressionStatement (expression_body
, source_reference
));
200 method
.body
= statement_body
;
202 method
.body
.owner
= method
.scope
;
204 /* lambda expressions should be usable like MemberAccess of a method */
205 symbol_reference
= method
;
207 if (method
== null) {
208 if (expression_body
!= null) {
209 expression_body
.check (analyzer
);
210 } else if (statement_body
!= null) {
211 statement_body
.check (analyzer
);
214 method
.check (analyzer
);
217 value_type
= new
MethodType (method
);