]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Convert ternary conditionals into if statements, fixes bug 543870 and bug
authorJürg Billeter <j@bitron.ch>
Sat, 29 Nov 2008 12:20:30 +0000 (12:20 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Sat, 29 Nov 2008 12:20:30 +0000 (12:20 +0000)
2008-11-29  Jürg Billeter  <j@bitron.ch>

* vala/Makefile.am:
* vala/valablock.vala:
* vala/valacodenode.vala:
* vala/valaconditionalexpression.vala:
* vala/valadeclarationstatement.vala:
* vala/valaexpression.vala:
* vala/valanullchecker.vala:
* vala/valastatementlist.vala:
* gobject/valaccodebasemodule.vala:
* gobject/valaccodegenerator.vala:
* gobject/valaccodemodule.vala:

Convert ternary conditionals into if statements,
fixes bug 543870 and bug 554594

svn path=/trunk/; revision=2083

12 files changed:
ChangeLog
gobject/valaccodebasemodule.vala
gobject/valaccodegenerator.vala
gobject/valaccodemodule.vala
vala/Makefile.am
vala/valablock.vala
vala/valacodenode.vala
vala/valaconditionalexpression.vala
vala/valadeclarationstatement.vala
vala/valaexpression.vala
vala/valanullchecker.vala
vala/valastatementlist.vala [new file with mode: 0644]

index 6ac82d2f8ec2e49281c19f826efa3a54da907ce7..33543fd2e10dc46ede8cab9dc4f273fa8fc42d0e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2008-11-29  Jürg Billeter  <j@bitron.ch>
+
+       * vala/Makefile.am:
+       * vala/valablock.vala:
+       * vala/valacodenode.vala:
+       * vala/valaconditionalexpression.vala:
+       * vala/valadeclarationstatement.vala:
+       * vala/valaexpression.vala:
+       * vala/valanullchecker.vala:
+       * vala/valastatementlist.vala:
+       * gobject/valaccodebasemodule.vala:
+       * gobject/valaccodegenerator.vala:
+       * gobject/valaccodemodule.vala:
+
+       Convert ternary conditionals into if statements,
+       fixes bug 543870 and bug 554594
+
 2008-11-28  Étienne BERSAC  <bersace03@laposte.net>
 
        * vapi/gobject-2.0.vapi:
index 88662c3d60e56bf43346a2c0e3d25f3b75570893..a7ac3d63d74ba157c43bbdeda93f6d90382d4d40 100644 (file)
@@ -135,6 +135,8 @@ public class Vala.CCodeBaseModule : CCodeModule {
 
        public Set<string> wrappers;
 
+       Map<string,string> variable_name_map = new HashMap<string,string> (str_hash, str_equal);
+
        public CCodeBaseModule (CCodeGenerator codegen, CCodeModule? next) {
                base (codegen, next);
 
@@ -1276,7 +1278,14 @@ public class Vala.CCodeBaseModule : CCodeModule {
        }
 
        public string get_variable_cname (string name) {
-               if (c_keywords.contains (name)) {
+               if (name[0] == '.') {
+                       // compiler-internal variable
+                       if (!variable_name_map.contains (name)) {
+                               variable_name_map.set (name, "_tmp%d".printf (next_temp_var_id));
+                               next_temp_var_id++;
+                       }
+                       return variable_name_map.get (name);
+               } else if (c_keywords.contains (name)) {
                        return name + "_";
                } else {
                        return name;
@@ -2886,10 +2895,6 @@ public class Vala.CCodeBaseModule : CCodeModule {
                expr.ccodenode = create_type_check (expr.expression.ccodenode, expr.type_reference);
        }
 
-       public override void visit_conditional_expression (ConditionalExpression expr) {
-               expr.ccodenode = new CCodeConditionalExpression ((CCodeExpression) expr.condition.ccodenode, (CCodeExpression) expr.true_expression.ccodenode, (CCodeExpression) expr.false_expression.ccodenode);
-       }
-
        public override void visit_lambda_expression (LambdaExpression l) {
                // use instance position from delegate
                var dt = (DelegateType) l.target_type;
index 8913ac52235e17d19421fcf626e16a35f9077b43..ca9f8a1b1b30ee7e30d9d4419a9b675382066361 100644 (file)
@@ -323,10 +323,6 @@ public class Vala.CCodeGenerator : CodeGenerator {
                head.visit_type_check (expr);
        }
 
-       public override void visit_conditional_expression (ConditionalExpression expr) {
-               head.visit_conditional_expression (expr);
-       }
-
        public override void visit_lambda_expression (LambdaExpression l) {
                head.visit_lambda_expression (l);
        }
index efd33e60dcef8a5ecb0ee36ef483149db9b04e75..bc49962d40233ad14eefee62d5e3b506314818fa 100644 (file)
@@ -320,10 +320,6 @@ public abstract class Vala.CCodeModule {
                next.visit_type_check (expr);
        }
 
-       public virtual void visit_conditional_expression (ConditionalExpression expr) {
-               next.visit_conditional_expression (expr);
-       }
-
        public virtual void visit_lambda_expression (LambdaExpression l) {
                next.visit_lambda_expression (l);
        }
index 74b65d0eb7b55d574b2c99a97676cc3dea02aa8d..029b7d831c62c51eae5558c6eefc0f83c8284b40 100644 (file)
@@ -122,6 +122,7 @@ libvalacore_la_VALASOURCES = \
        valasourcelocation.vala \
        valasourcereference.vala \
        valastatement.vala \
+       valastatementlist.vala \
        valastringliteral.vala \
        valastruct.vala \
        valaswitchlabel.vala \
index 330daa7f0afc187cf471773a4858e311a5cbcf26..8eb3516c0be7f41186a267ceb6db03d591ed48a4 100644 (file)
@@ -64,7 +64,18 @@ public class Vala.Block : Symbol, Statement {
         * @return statement list
         */
        public Gee.List<Statement> get_statements () {
-               return new ReadOnlyList<Statement> (statement_list);
+               var list = new ArrayList<Statement> ();
+               foreach (Statement stmt in statement_list) {
+                       var stmt_list = stmt as StatementList;
+                       if (stmt_list != null) {
+                               for (int i = 0; i < stmt_list.length; i++) {
+                                       list.add (stmt_list.get (i));
+                               }
+                       } else {
+                               list.add (stmt);
+                       }
+               }
+               return list;
        }
        
        /**
@@ -75,7 +86,11 @@ public class Vala.Block : Symbol, Statement {
        public void add_local_variable (LocalVariable local) {
                local_variables.add (local);
        }
-       
+
+       public void remove_local_variable (LocalVariable local) {
+               local_variables.remove (local);
+       }
+
        /**
         * Returns a copy of the list of local variables.
         *
@@ -103,22 +118,60 @@ public class Vala.Block : Symbol, Statement {
                checked = true;
 
                owner = analyzer.current_symbol.scope;
+
+               var old_symbol = analyzer.current_symbol;
                analyzer.current_symbol = this;
 
-               foreach (Statement stmt in statement_list) {
-                       stmt.check (analyzer);
+               for (int i = 0; i < statement_list.size; i++) {
+                       statement_list[i].check (analyzer);
                }
 
                foreach (LocalVariable local in get_local_variables ()) {
                        local.active = false;
                }
 
-               foreach (Statement stmt in get_statements ()) {
+               foreach (Statement stmt in statement_list) {
                        add_error_types (stmt.get_error_types ());
                }
 
-               analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
+               analyzer.current_symbol = old_symbol;
 
                return !error;
        }
+
+       public void insert_before (Statement stmt, Statement new_stmt) {
+               for (int i = 0; i < statement_list.size; i++) {
+                       var stmt_list = statement_list[i] as StatementList;
+                       if (stmt_list != null) {
+                               for (int j = 0; j < stmt_list.length; j++) {
+                                       if (stmt_list.get (j) == stmt) {
+                                               stmt_list.insert (j, new_stmt);
+                                               break;
+                                       }
+                               }
+                       } else if (statement_list[i] == stmt) {
+                               stmt_list = new StatementList (source_reference);
+                               stmt_list.add (new_stmt);
+                               stmt_list.add (stmt);
+                               statement_list[i] = stmt_list;
+                       }
+               }
+       }
+
+       public void replace_statement (Statement old_stmt, Statement new_stmt) {
+               for (int i = 0; i < statement_list.size; i++) {
+                       var stmt_list = statement_list[i] as StatementList;
+                       if (stmt_list != null) {
+                               for (int j = 0; j < stmt_list.length; j++) {
+                                       if (stmt_list.get (j) == old_stmt) {
+                                               stmt_list.set (j, new_stmt);
+                                               break;
+                                       }
+                               }
+                       } else if (statement_list[i] == old_stmt) {
+                               statement_list[i] = new_stmt;
+                               break;
+                       }
+               }
+       }
 }
index 88e21dde41e3651f29de24584d91c660753ec3dd..4596e45c7fa8a338507f6807470b211017b65190 100644 (file)
@@ -83,6 +83,8 @@ public abstract class Vala.CodeNode {
 
        private CCodeNode? _ccodenode;
 
+       static int last_temp_nr = 0;
+
        /**
         * Specifies the exceptions that can be thrown by this node or a child node
         */
@@ -183,4 +185,8 @@ public abstract class Vala.CodeNode {
 
        public virtual void get_used_variables (Collection<LocalVariable> collection) {
        }
+
+       public string get_temp_name () {
+               return "." + (++last_temp_nr).to_string ();
+       }
 }
index 0ba4a859a285bebe0191b5288d19e2b4583c9161..f53cd1a155063563aaf694e80898cabf9c169c64 100644 (file)
@@ -29,18 +29,46 @@ public class Vala.ConditionalExpression : Expression {
        /**
         * The condition.
         */
-       public Expression condition { get; set; }
-       
+       public Expression condition {
+               get {
+                       return _condition;
+               }
+               set {
+                       _condition = value;
+                       _condition.parent_node = this;
+               }
+       }
+
        /**
         * The expression to be evaluated if the condition holds.
         */
-       public Expression true_expression { get; set; }
+       public Expression true_expression {
+               get {
+                       return _true_expression;
+               }
+               set {
+                       _true_expression = value;
+                       _true_expression.parent_node = this;
+               }
+       }
 
        /**
         * The expression to be evaluated if the condition doesn't hold.
         */
-       public Expression false_expression { get; set; }
-       
+       public Expression false_expression {
+               get {
+                       return _false_expression;
+               }
+               set {
+                       _false_expression = value;
+                       _false_expression.parent_node = this;
+               }
+       }
+
+       Expression _condition;
+       Expression _true_expression;
+       Expression _false_expression;
+
        /**
         * Creates a new conditional expression.
         *
@@ -77,17 +105,35 @@ public class Vala.ConditionalExpression : Expression {
 
                checked = true;
 
-               if (!condition.check (analyzer) || !false_expression.check (analyzer) || !true_expression.check (analyzer)) {
-                       return false;
-               }
+               // convert ternary expression into if statement
+               // required for flow analysis and exception handling
 
-               if (!condition.value_type.compatible (analyzer.bool_type)) {
-                       error = true;
-                       Report.error (condition.source_reference, "Condition must be boolean");
+               string temp_name = get_temp_name ();
+
+               true_expression.target_type = target_type;
+               false_expression.target_type = target_type;
+
+               var true_local = new LocalVariable (null, temp_name, true_expression, true_expression.source_reference);
+               var true_block = new Block (true_expression.source_reference);
+               var true_decl = new DeclarationStatement (true_local, true_expression.source_reference);
+               true_block.add_statement (true_decl);
+
+               var false_local = new LocalVariable (null, temp_name, false_expression, false_expression.source_reference);
+               var false_block = new Block (false_expression.source_reference);
+               var false_decl = new DeclarationStatement (false_local, false_expression.source_reference);
+               false_block.add_statement (false_decl);
+
+               var if_stmt = new IfStatement (condition, true_block, false_block, source_reference);
+               if (!if_stmt.check (analyzer)) {
                        return false;
                }
 
-               /* FIXME: support memory management */
+               true_expression = true_local.initializer;
+               false_expression = false_local.initializer;
+
+               true_block.remove_local_variable (true_local);
+               false_block.remove_local_variable (false_local);
+
                if (false_expression.value_type.compatible (true_expression.value_type)) {
                        value_type = true_expression.value_type.copy ();
                } else if (true_expression.value_type.compatible (false_expression.value_type)) {
@@ -98,6 +144,33 @@ public class Vala.ConditionalExpression : Expression {
                        return false;
                }
 
-               return !error;
+               value_type.value_owned = (true_expression.value_type.value_owned || false_expression.value_type.value_owned);
+
+               var local = new LocalVariable (value_type, temp_name, null, source_reference);
+               var decl = new DeclarationStatement (local, source_reference);
+               decl.check (analyzer);
+
+               true_expression.target_type = value_type;
+               false_expression.target_type = value_type;
+
+               var true_stmt = new ExpressionStatement (new Assignment (new MemberAccess.simple (local.name, true_expression.source_reference), true_expression, AssignmentOperator.SIMPLE, true_expression.source_reference), true_expression.source_reference);
+               true_stmt.check (analyzer);
+
+               var false_stmt = new ExpressionStatement (new Assignment (new MemberAccess.simple (local.name, false_expression.source_reference), false_expression, AssignmentOperator.SIMPLE, false_expression.source_reference), false_expression.source_reference);
+               false_stmt.check (analyzer);
+
+               true_block.replace_statement (true_decl, true_stmt);
+               false_block.replace_statement (false_decl, false_stmt);
+
+               insert_statement ((Block) analyzer.current_symbol, decl);
+               insert_statement ((Block) analyzer.current_symbol, if_stmt);
+
+               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;
        }
 }
index 0cc28fbd7c59a5ef3d3281f414c5bee92dad1c85..9e3cc0377be99eb3d2d65ef4bbf1c3240c5e540b 100644 (file)
@@ -29,7 +29,19 @@ public class Vala.DeclarationStatement : CodeNode, Statement {
        /**
         * The local variable or constant declaration.
         */
-       public Symbol declaration { get; set; }
+       public Symbol declaration {
+               get {
+                       return _declaration;
+               }
+               set {
+                       _declaration = value;
+                       if (_declaration != null) {
+                               _declaration.parent_node = this;
+                       }
+               }
+       }
+
+       Symbol _declaration;
 
        /**
         * Creates a new declaration statement.
index 79ca8b13c61f8b0c828df6b2193c9fb2b027c6e4..11d43950a5b416127ce26a902e9dd0b270683a43 100644 (file)
@@ -84,4 +84,25 @@ public abstract class Vala.Expression : CodeNode {
        public virtual bool is_non_null () {
                return false;
        }
+
+       public Statement? parent_statement {
+               get {
+                       var expr = parent_node as Expression;
+                       var stmt = parent_node as Statement;
+                       var local = parent_node as LocalVariable;
+                       if (stmt != null) {
+                               return stmt;
+                       } else if (expr != null) {
+                               return expr.parent_statement;
+                       } else if (local != null) {
+                               return (Statement) local.parent_node;
+                       } else {
+                               return null;
+                       }
+               }
+       }
+
+       public void insert_statement (Block block, Statement stmt) {
+               block.insert_before (parent_statement, stmt);
+       }
 }
index 7cd940d75b72788bd06c924aa5b43a3aee6e66c9..3263c25504398c9c814a6ddc869f39c3bbd1cec5 100644 (file)
@@ -235,10 +235,6 @@ public class Vala.NullChecker : CodeVisitor {
                expr.accept_children (this);
        }
 
-       public override void visit_conditional_expression (ConditionalExpression expr) {
-               check_non_null (expr.condition);
-       }
-
        public override void visit_lambda_expression (LambdaExpression l) {
                l.accept_children (this);
        }
diff --git a/vala/valastatementlist.vala b/vala/valastatementlist.vala
new file mode 100644 (file)
index 0000000..a653f02
--- /dev/null
@@ -0,0 +1,57 @@
+/* valastatementlist.vala
+ *
+ * Copyright (C) 2008  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using Gee;
+
+public class Vala.StatementList : CodeNode, Statement {
+       private Gee.List<Statement> list = new ArrayList<Statement> ();
+
+       public int length {
+               get { return list.size; }
+       }
+
+       public StatementList (SourceReference source_reference) {
+               this.source_reference = source_reference;
+       }
+
+       public Statement get (int index) {
+               return list.get (index);
+       }
+
+       public void set (int index, Statement stmt) {
+               list.set (index, stmt);
+       }
+
+       public void add (Statement stmt) {
+               list.add (stmt);
+       }
+
+       public void insert (int index, Statement stmt) {
+               list.insert (index, stmt);
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               foreach (Statement stmt in list) {
+                       stmt.accept (visitor);
+               }
+       }
+}