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>
26 * Represents a lambda expression in the source code. Lambda expressions are
27 * anonymous methods with implicitly typed parameters.
29 public class Vala
.LambdaExpression
: Expression
{
31 * The expression body of this lambda expression. Only one of
32 * expression_body or statement_body may be set.
34 public Expression expression_body
{ get; set; }
37 * The statement body of this lambda expression. Only one of
38 * expression_body or statement_body may be set.
40 public Block statement_body
{ get; set; }
43 * The generated method.
45 public Method method
{ get; set; }
47 private List
<string> parameters
= new ArrayList
<string> ();
50 * Creates a new lambda expression.
52 * @param expression_body expression body
53 * @param source_reference reference to source code
54 * @return newly created lambda expression
56 public LambdaExpression (Expression expression_body
, SourceReference source_reference
) {
57 this
.source_reference
= source_reference
;
58 this
.expression_body
= expression_body
;
62 * Creates a new lambda expression with statement body.
64 * @param statement_body statement body
65 * @param source_reference reference to source code
66 * @return newly created lambda expression
68 public LambdaExpression
.with_statement_body (Block statement_body
, SourceReference source_reference
) {
69 this
.statement_body
= statement_body
;
70 this
.source_reference
= source_reference
;
74 * Appends implicitly typed parameter.
76 * @param param parameter name
78 public void add_parameter (string param
) {
79 parameters
.add (param
);
83 * Returns copy of parameter list.
85 * @return parameter list
87 public List
<string> get_parameters () {
88 return new ReadOnlyList
<string> (parameters
);
91 public override void accept (CodeVisitor visitor
) {
92 visitor
.visit_lambda_expression (this
);
94 visitor
.visit_expression (this
);
97 public override void accept_children (CodeVisitor visitor
) {
99 if (expression_body
!= null) {
100 expression_body
.accept (visitor
);
101 visitor
.visit_end_full_expression (expression_body
);
102 } else if (statement_body
!= null) {
103 statement_body
.accept (visitor
);
106 method
.accept (visitor
);
110 public override bool is_pure () {
114 string get_lambda_name (SemanticAnalyzer analyzer
) {
115 var result
= "_lambda%d_".printf (analyzer
.next_lambda_id
);
117 analyzer
.next_lambda_id
++;
122 public override bool check (SemanticAnalyzer analyzer
) {
129 if (!(target_type is DelegateType
)) {
131 Report
.error (source_reference
, "lambda expression not allowed in this context");
135 var cb
= (Delegate
) ((DelegateType
) target_type
).delegate_symbol
;
136 method
= new
Method (get_lambda_name (analyzer
), cb
.return_type
);
137 if (!cb
.has_target
|| !analyzer
.is_in_instance_method ()) {
138 method
.binding
= MemberBinding
.STATIC
;
140 var sym
= analyzer
.current_symbol
;
141 while (method
.this_parameter
== null) {
142 if (sym is Property
) {
143 var prop
= (Property
) sym
;
144 method
.this_parameter
= prop
.this_parameter
;
145 } else if (sym is Constructor
) {
146 var c
= (Constructor
) sym
;
147 method
.this_parameter
= c
.this_parameter
;
148 } else if (sym is Destructor
) {
149 var d
= (Destructor
) sym
;
150 method
.this_parameter
= d
.this_parameter
;
151 } else if (sym is Method
) {
152 var m
= (Method
) sym
;
153 method
.this_parameter
= m
.this_parameter
;
156 sym
= sym
.parent_symbol
;
159 method
.owner
= analyzer
.current_symbol
.scope
;
161 var lambda_params
= get_parameters ();
162 Iterator
<string> lambda_param_it
= lambda_params
.iterator ();
164 if (cb
.sender_type
!= null && lambda_params
.size
== cb
.get_parameters ().size
+ 1) {
165 // lambda expression has sender parameter
166 lambda_param_it
.next ();
168 string lambda_param
= lambda_param_it
.get ();
169 var param
= new
FormalParameter (lambda_param
, cb
.sender_type
);
170 method
.add_parameter (param
);
173 foreach (FormalParameter cb_param
in cb
.get_parameters ()) {
174 if (!lambda_param_it
.next ()) {
175 /* lambda expressions are allowed to have less parameters */
179 string lambda_param
= lambda_param_it
.get ();
180 var param
= new
FormalParameter (lambda_param
, cb_param
.parameter_type
);
181 method
.add_parameter (param
);
184 if (lambda_param_it
.next ()) {
185 /* lambda expressions may not expect more parameters */
187 Report
.error (source_reference
, "lambda expression: too many parameters");
191 foreach (var error_type
in cb
.get_error_types ()) {
192 method
.add_error_type (error_type
.copy ());
195 if (expression_body
!= null) {
196 var block
= new
Block (source_reference
);
197 block
.scope
.parent_scope
= method
.scope
;
199 if (method
.return_type
.data_type
!= null) {
200 block
.add_statement (new
ReturnStatement (expression_body
, source_reference
));
202 block
.add_statement (new
ExpressionStatement (expression_body
, source_reference
));
207 method
.body
= statement_body
;
209 method
.body
.owner
= method
.scope
;
211 /* lambda expressions should be usable like MemberAccess of a method */
212 symbol_reference
= method
;
214 if (method
== null) {
215 if (expression_body
!= null) {
216 expression_body
.check (analyzer
);
217 } else if (statement_body
!= null) {
218 statement_body
.check (analyzer
);
221 method
.check (analyzer
);
224 value_type
= new
MethodType (method
);
225 value_type
.value_owned
= target_type
.value_owned
;
230 public override void get_used_variables (Collection
<LocalVariable
> collection
) {
231 // require captured variables to be initialized
232 if (method
.closure
) {
233 method
.get_captured_variables (collection
);