[vala] Support ref and out parameters in lambda expressions



commit 3ee508f5fdf332978848d344049bdeeb3fbe741a
Author: Luca Bruno <lucabru src gnome org>
Date:   Sat Apr 16 12:55:35 2011 +0200

    Support ref and out parameters in lambda expressions
    
    Fixes bug 622570.

 tests/Makefile.am              |    1 +
 tests/methods/bug622570.vala   |   13 +++++++
 vala/valacodewriter.vala       |   17 +++++++--
 vala/valagenieparser.vala      |   10 +++--
 vala/valalambdaexpression.vala |   21 +++++------
 vala/valaparameter.vala        |    2 +-
 vala/valaparser.vala           |   78 ++++++++++++++++++++++++++++++++++-----
 7 files changed, 112 insertions(+), 30 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 693551d..a4b1bed 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -37,6 +37,7 @@ TESTS = \
 	methods/bug599892.vala \
 	methods/bug613483.vala \
 	methods/bug620673.vala \
+	methods/bug622570.vala \
 	methods/bug642899.vala \
 	methods/bug646345.vala \
 	methods/bug648320.vala \
diff --git a/tests/methods/bug622570.vala b/tests/methods/bug622570.vala
new file mode 100644
index 0000000..f8b4e91
--- /dev/null
+++ b/tests/methods/bug622570.vala
@@ -0,0 +1,13 @@
+delegate int Deleg1 (ref int foo);
+delegate void Deleg2 (out Value foo, ref int bar);
+
+void main () {
+	int a = 3, b = 4;
+	Value c;
+	Deleg1 d1 = ref foo => foo + 5;
+	Deleg2 d2 = (out foo, ref bar) => { foo = 10; bar = 3; };
+	assert (d1 (ref a) == 8);
+	d2 (out c, ref b);
+	assert (c == 10);
+	assert (b == 3);
+}
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index ff5b413..ee5daf1 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1924,12 +1924,21 @@ public class Vala.CodeWriter : CodeVisitor {
 	public override void visit_lambda_expression (LambdaExpression expr) {
 		write_string ("(");
 		var params = expr.get_parameters ();
-		if (params.size != 0) {
-			for (var i = 0; i < params.size - 1; ++ i) {
-				write_string (params[i]);
+		int i = 1;
+		foreach (var param in params) {
+			if (i > 1) {
 				write_string (", ");
 			}
-			write_string (params[params.size - 1]);
+
+			if (param.direction == ParameterDirection.REF) {
+				write_string ("ref ");
+			} else if (param.direction == ParameterDirection.OUT) {
+				write_string ("out ");
+			}
+
+			write_identifier (param.name);
+
+			i++;
 		}
 		write_string (") =>");
 		if (expr.statement_body != null) {
diff --git a/vala/valagenieparser.vala b/vala/valagenieparser.vala
index 89e5ea7..0de741c 100644
--- a/vala/valagenieparser.vala
+++ b/vala/valagenieparser.vala
@@ -1522,19 +1522,21 @@ public class Vala.Genie.Parser : CodeVisitor {
 
 	Expression parse_lambda_expression () throws ParseError {
 		var begin = get_location ();
-		List<string> params = new ArrayList<string> ();
+		List<Parameter> params = new ArrayList<Parameter> ();
 		
 		expect (TokenType.DEF);
 		
 		if (accept (TokenType.OPEN_PARENS)) {
 			if (current () != TokenType.CLOSE_PARENS) {
 				do {
-					params.add (parse_identifier ());
+					var param = new Parameter (parse_identifier (), null, get_src (get_location ()));
+					params.add (param);
 				} while (accept (TokenType.COMMA));
 			}
 			expect (TokenType.CLOSE_PARENS);
 		} else {
-			params.add (parse_identifier ());
+			var param = new Parameter (parse_identifier (), null, get_src (get_location ()));
+			params.add (param);
 		}
 
 
@@ -1550,7 +1552,7 @@ public class Vala.Genie.Parser : CodeVisitor {
 		}
 
 
-		foreach (string param in params) {
+		foreach (var param in params) {
 			lambda.add_parameter (param);
 		}
 		return lambda;
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
index c09aea8..ecfe251 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -44,7 +44,7 @@ public class Vala.LambdaExpression : Expression {
 	 */
 	public Method method { get; set; }
 
-	private List<string> parameters = new ArrayList<string> ();
+	private List<Parameter> parameters = new ArrayList<Parameter> ();
 
 	/**
 	 * Creates a new lambda expression.
@@ -75,7 +75,7 @@ public class Vala.LambdaExpression : Expression {
 	 *
 	 * @param param parameter name
 	 */
-	public void add_parameter (string param) {
+	public void add_parameter (Parameter param) {
 		parameters.add (param);
 	}
 	
@@ -84,7 +84,7 @@ public class Vala.LambdaExpression : Expression {
 	 *
 	 * @return parameter list
 	 */
-	public List<string> get_parameters () {
+	public List<Parameter> get_parameters () {
 		return parameters;
 	}
 	
@@ -173,15 +173,15 @@ public class Vala.LambdaExpression : Expression {
 		}
 
 		var lambda_params = get_parameters ();
-		Iterator<string> lambda_param_it = lambda_params.iterator ();
+		Iterator<Parameter> lambda_param_it = lambda_params.iterator ();
 
 		if (cb.sender_type != null && lambda_params.size == cb.get_parameters ().size + 1) {
 			// lambda expression has sender parameter
 			lambda_param_it.next ();
 
-			string lambda_param = lambda_param_it.get ();
-			var param = new Parameter (lambda_param, cb.sender_type);
-			method.add_parameter (param);
+			Parameter lambda_param = lambda_param_it.get ();
+			lambda_param.variable_type = cb.sender_type;
+			method.add_parameter (lambda_param);
 		}
 
 		foreach (Parameter cb_param in cb.get_parameters ()) {
@@ -190,10 +190,9 @@ public class Vala.LambdaExpression : Expression {
 				break;
 			}
 
-			string lambda_param = lambda_param_it.get ();
-			var param_type = cb_param.variable_type.get_actual_type (target_type, null, this);
-			var param = new Parameter (lambda_param, param_type);
-			method.add_parameter (param);
+			Parameter lambda_param = lambda_param_it.get ();
+			lambda_param.variable_type = cb_param.variable_type.get_actual_type (target_type, null, this);
+			method.add_parameter (lambda_param);
 		}
 
 		if (lambda_param_it.next ()) {
diff --git a/vala/valaparameter.vala b/vala/valaparameter.vala
index faab5af..ab4d4a3 100644
--- a/vala/valaparameter.vala
+++ b/vala/valaparameter.vala
@@ -76,7 +76,7 @@ public class Vala.Parameter : Variable {
 	 * @param source reference to source code
 	 * @return       newly created formal parameter
 	 */
-	public Parameter (string name, DataType variable_type, SourceReference? source_reference = null) {
+	public Parameter (string name, DataType? variable_type, SourceReference? source_reference = null) {
 		base (variable_type, name, null, source_reference);
 
 		access = SymbolAccessibility.PUBLIC;
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index ad97da8..60c7a60 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -1352,18 +1352,34 @@ public class Vala.Parser : CodeVisitor {
 		}
 	}
 
+	Parameter parse_lambda_parameter () throws ParseError {
+		var begin = get_location ();
+		var direction = ParameterDirection.IN;
+		if (accept (TokenType.OUT)) {
+			direction = ParameterDirection.OUT;
+		} else if (accept (TokenType.REF)) {
+			direction = ParameterDirection.REF;
+		}
+
+		string id = parse_identifier ();
+
+		var param = new Parameter (id, null, get_src (begin));
+		param.direction = direction;
+		return param;
+	}
+
 	Expression parse_lambda_expression () throws ParseError {
 		var begin = get_location ();
-		List<string> params = new ArrayList<string> ();
+		List<Parameter> params = new ArrayList<Parameter> ();
 		if (accept (TokenType.OPEN_PARENS)) {
 			if (current () != TokenType.CLOSE_PARENS) {
 				do {
-					params.add (parse_identifier ());
+					params.add (parse_lambda_parameter ());
 				} while (accept (TokenType.COMMA));
 			}
 			expect (TokenType.CLOSE_PARENS);
 		} else {
-			params.add (parse_identifier ());
+			params.add (parse_lambda_parameter ());
 		}
 		expect (TokenType.LAMBDA);
 
@@ -1375,7 +1391,7 @@ public class Vala.Parser : CodeVisitor {
 			var expr = parse_expression ();
 			lambda = new LambdaExpression (expr, get_src (begin));
 		}
-		foreach (string param in params) {
+		foreach (var param in params) {
 			lambda.add_parameter (param);
 		}
 		return lambda;
@@ -1398,14 +1414,13 @@ public class Vala.Parser : CodeVisitor {
 	}
 
 	Expression parse_expression () throws ParseError {
+		if (is_lambda_expression ()) {
+			return parse_lambda_expression ();
+		}
+
 		var begin = get_location ();
-		Expression expr = parse_conditional_expression ();
 
-		if (current () == TokenType.LAMBDA) {
-			rollback (begin);
-			var lambda = parse_lambda_expression ();
-			return lambda;
-		}
+		Expression expr = parse_conditional_expression ();
 
 		while (true) {
 			var operator = get_assignment_operator (current ());
@@ -1582,6 +1597,49 @@ public class Vala.Parser : CodeVisitor {
 		}
 	}
 
+	bool is_lambda_expression () {
+		var begin = get_location ();
+
+		switch (current ()) {
+		case TokenType.OUT:
+		case TokenType.REF:
+			next ();
+			if (accept (TokenType.IDENTIFIER) && accept (TokenType.LAMBDA)) {
+				rollback (begin);
+				return true;
+			}
+			break;
+		case TokenType.IDENTIFIER:
+			next ();
+			if (accept (TokenType.LAMBDA)) {
+				rollback (begin);
+				return true;
+			}
+			break;
+		case TokenType.OPEN_PARENS:
+			next ();
+			if (current () != TokenType.CLOSE_PARENS) {
+				do {
+					if (current () == TokenType.OUT || current () == TokenType.REF) {
+						next ();
+					}
+					if (!accept (TokenType.IDENTIFIER)) {
+						rollback (begin);
+						return false;
+					}
+				} while (accept (TokenType.COMMA));
+			}
+			if (accept (TokenType.CLOSE_PARENS) && accept (TokenType.LAMBDA)) {
+				rollback (begin);
+				return true;
+			}
+			break;
+		}
+
+		rollback (begin);
+		return false;
+	}
+
 	Block parse_embedded_statement () throws ParseError {
 		if (current () == TokenType.OPEN_BRACE) {
 			var block = parse_block ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]