From: Luca Bruno Date: Sat, 16 Apr 2011 10:55:35 +0000 (+0200) Subject: Support ref and out parameters in lambda expressions X-Git-Tag: 0.13.1~44 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3ee508f5fdf332978848d344049bdeeb3fbe741a;p=thirdparty%2Fvala.git Support ref and out parameters in lambda expressions Fixes bug 622570. --- diff --git a/tests/Makefile.am b/tests/Makefile.am index 693551d85..a4b1beddd 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 000000000..f8b4e9113 --- /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 ff5b413a8..ee5daf111 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 89e5ea732..0de741cc5 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 params = new ArrayList (); + List params = new ArrayList (); 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 c09aea82b..ecfe25106 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 parameters = new ArrayList (); + private List parameters = new ArrayList (); /** * 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 get_parameters () { + public List get_parameters () { return parameters; } @@ -173,15 +173,15 @@ public class Vala.LambdaExpression : Expression { } var lambda_params = get_parameters (); - Iterator lambda_param_it = lambda_params.iterator (); + Iterator 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 faab5afe6..ab4d4a3b0 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 ad97da879..60c7a6039 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 params = new ArrayList (); + List params = new ArrayList (); 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 ();