Support constructor chain up to GObject using Object (...)
[vala-lang.git] / vala / valalambdaexpression.vala
blob0f0bb29979787f1ff30682b6af11389eb8b71528
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
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 {
30 /**
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; }
36 /**
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; }
42 /**
43 * The generated method.
45 public Method method { get; set; }
47 private List<string> parameters = new ArrayList<string> ();
49 /**
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;
61 /**
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;
73 /**
74 * Appends implicitly typed parameter.
76 * @param param parameter name
78 public void add_parameter (string param) {
79 parameters.add (param);
82 /**
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) {
98 if (method == null) {
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);
105 } else {
106 method.accept (visitor);
110 public override bool is_pure () {
111 return false;
114 string get_lambda_name (SemanticAnalyzer analyzer) {
115 var result = "_lambda%d_".printf (analyzer.next_lambda_id);
117 analyzer.next_lambda_id++;
119 return result;
122 public override bool check (SemanticAnalyzer analyzer) {
123 if (checked) {
124 return !error;
127 checked = true;
129 if (!(target_type is DelegateType)) {
130 error = true;
131 Report.error (source_reference, "lambda expression not allowed in this context");
132 return false;
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;
139 } else {
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 */
176 break;
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 */
186 error = true;
187 Report.error (source_reference, "lambda expression: too many parameters");
188 return false;
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));
201 } else {
202 block.add_statement (new ExpressionStatement (expression_body, source_reference));
205 method.body = block;
206 } else {
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);
220 } else {
221 method.check (analyzer);
224 value_type = new MethodType (method);
225 value_type.value_owned = target_type.value_owned;
227 return !error;
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);