From: Jürg Billeter Date: Wed, 27 Jan 2010 01:13:24 +0000 (+0100) Subject: Implement coalescing operator ?? X-Git-Tag: 0.7.10~32 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b319ccfbfd263417ef0724bf3346eb3765cf75a9;p=thirdparty%2Fvala.git Implement coalescing operator ?? Based on patch by Marc-André Lureau, fixes bug 580816. --- diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala index 4400f0250..01cae0b87 100644 --- a/vala/valabinaryexpression.vala +++ b/vala/valabinaryexpression.vala @@ -24,7 +24,7 @@ /** * Represents an expression with two operands in the source code. * - * Supports +, -, *, /, %, <<, >>, <, >, <=, >=, ==, !=, &, |, ^, &&, ||. + * Supports +, -, *, /, %, <<, >>, <, >, <=, >=, ==, !=, &, |, ^, &&, ||, ??. */ public class Vala.BinaryExpression : Expression { /** @@ -118,6 +118,7 @@ public class Vala.BinaryExpression : Expression { case BinaryOperator.AND: return "&&"; case BinaryOperator.OR: return "||"; case BinaryOperator.IN: return "in"; + case BinaryOperator.COALESCE: return "??"; } assert_not_reached (); @@ -206,6 +207,38 @@ public class Vala.BinaryExpression : Expression { return true; } + if (operator == BinaryOperator.COALESCE) { + var local = new LocalVariable (null, get_temp_name (), left, source_reference); + var decl = new DeclarationStatement (local, source_reference); + decl.check (analyzer); + + var right_stmt = new ExpressionStatement (new Assignment (new MemberAccess.simple (local.name, right.source_reference), right, AssignmentOperator.SIMPLE, right.source_reference), right.source_reference); + + var true_block = new Block (source_reference); + + true_block.add_statement (right_stmt); + + var cond = new BinaryExpression (BinaryOperator.EQUALITY, new MemberAccess.simple (local.name, left.source_reference), new NullLiteral (source_reference), source_reference); + + var if_stmt = new IfStatement (cond, true_block, null, source_reference); + + insert_statement (analyzer.insert_block, decl); + insert_statement (analyzer.insert_block, if_stmt); + + if (!if_stmt.check (analyzer)) { + error = true; + return false; + } + + var ma = new MemberAccess.simple (local.name, source_reference); + ma.target_type = target_type; + ma.check (analyzer); + + parent_node.replace_expression (this, ma); + + return true; + } + if (!left.check (analyzer) || !right.check (analyzer)) { /* if there were any errors in inner expressions, skip type check */ error = true; @@ -432,5 +465,6 @@ public enum Vala.BinaryOperator { BITWISE_XOR, AND, OR, - IN + IN, + COALESCE } diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala index b94f77795..89fcab079 100644 --- a/vala/valacodewriter.vala +++ b/vala/valacodewriter.vala @@ -1586,6 +1586,9 @@ public class Vala.CodeWriter : CodeVisitor { case BinaryOperator.IN: write_string (" in "); break; + case BinaryOperator.COALESCE: + write_string (" ?? "); + break; default: assert_not_reached (); } diff --git a/vala/valaparser.vala b/vala/valaparser.vala index 999976ebf..b3d3454c5 100644 --- a/vala/valaparser.vala +++ b/vala/valaparser.vala @@ -1217,9 +1217,20 @@ public class Vala.Parser : CodeVisitor { return left; } + Expression parse_coalescing_expression () throws ParseError { + var begin = get_location (); + var left = parse_conditional_or_expression (); + if (accept (TokenType.OP_COALESCING)) { + var right = parse_coalescing_expression (); + return new BinaryExpression (BinaryOperator.COALESCE, left, right, get_src (begin)); + } else { + return left; + } + } + Expression parse_conditional_expression () throws ParseError { var begin = get_location (); - var condition = parse_conditional_or_expression (); + var condition = parse_coalescing_expression (); if (accept (TokenType.INTERR)) { var true_expr = parse_expression (); expect (TokenType.COLON); diff --git a/vala/valascanner.vala b/vala/valascanner.vala index 9a1d3eabc..40e19751c 100644 --- a/vala/valascanner.vala +++ b/vala/valascanner.vala @@ -688,6 +688,10 @@ public class Vala.Scanner { case '?': type = TokenType.INTERR; current++; + if (current < end && current[0] == '?') { + type = TokenType.OP_COALESCING; + current++; + } break; case '|': type = TokenType.BITWISE_OR; diff --git a/vala/valatokentype.vala b/vala/valatokentype.vala index bfacde16d..61b485958 100644 --- a/vala/valatokentype.vala +++ b/vala/valatokentype.vala @@ -93,6 +93,7 @@ public enum Vala.TokenType { NULL, OUT, OP_AND, + OP_COALESCING, OP_DEC, OP_EQ, OP_GE,