[vala/staging] vala: Properly parse and handle chained initialization of members



commit 86bc23f2d7295ae3b2f5f79449d2c5a4a7a93a58
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Tue Feb 16 22:42:00 2021 +0100

    vala: Properly parse and handle chained initialization of members
    
    Make MemberInitializer an Expression, so it is possible to descibe
    nested/chained member initializers in the AST.
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/1137

 tests/Makefile.am                               |  2 +
 tests/objects/member-initializer-chained-2.vala | 18 ++++++++
 tests/objects/member-initializer-chained.vala   | 61 +++++++++++++++++++++++++
 vala/valagenieparser.vala                       | 10 +++-
 vala/valamemberinitializer.vala                 | 11 ++---
 vala/valaobjectcreationexpression.vala          | 27 +++++++++++
 vala/valaparser.vala                            | 10 +++-
 7 files changed, 131 insertions(+), 8 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3294f9a03..612808724 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -451,6 +451,8 @@ TESTS = \
        objects/interface-property-override.vala \
        objects/interface-virtual-override.vala \
        objects/member-initializer-base-properties.vala \
+       objects/member-initializer-chained.vala \
+       objects/member-initializer-chained-2.vala \
        objects/member-initializer-property.vala \
        objects/member-initializer-property-owned-setter.vala \
        objects/methods.vala \
diff --git a/tests/objects/member-initializer-chained-2.vala b/tests/objects/member-initializer-chained-2.vala
new file mode 100644
index 000000000..b8b12d616
--- /dev/null
+++ b/tests/objects/member-initializer-chained-2.vala
@@ -0,0 +1,18 @@
+class Foo : Object {
+}
+
+class Bar {
+       public Foo a;
+       public Foo b { get; set; }
+       public Foo c;
+}
+
+void main () {
+       var bar = new Bar () {
+               a = b = c = new Foo ()
+       };
+       assert (bar.a != null);
+       assert (bar.a == bar.b);
+       assert (bar.a == bar.c);
+       assert (bar.a.ref_count == 4);
+}
diff --git a/tests/objects/member-initializer-chained.vala b/tests/objects/member-initializer-chained.vala
new file mode 100644
index 000000000..106076a6f
--- /dev/null
+++ b/tests/objects/member-initializer-chained.vala
@@ -0,0 +1,61 @@
+class Foo {
+    public int x;
+    public int y { get; set; }
+    public int z;
+}
+
+class Bar : Foo {
+    public Bar () {
+               x = 4711;
+               y = 4711;
+               z = 4711;
+               {
+                       var foo = new Foo () {
+                               x = y = z = 23
+                       };
+                       assert (foo.x == 23);
+                       assert (foo.y == 23);
+                       assert (foo.y == 23);
+               }
+               {
+                       var foo2 = new Foo () {
+                               z = 42,
+                               y = z,
+                               x = y
+                       };
+                       assert (foo2.x == 4711);
+                       assert (foo2.y == 4711);
+                       assert (foo2.z == 42);
+               }
+               assert (x == 4711);
+               assert (y == 4711);
+               assert (z == 4711);
+    }
+}
+
+int i = 67;
+
+int get_int () {
+       return i++;
+}
+
+void main () {
+       {
+               var bar = new Bar () {
+                       x = y = z = get_int ()
+               };
+               assert (bar.x == 67);
+               assert (bar.y == 67);
+               assert (bar.z == 67);
+       }
+       {
+               var bar = new Bar () {
+                       x = 23,
+                       y = 42,
+                       z = 67
+               };
+               assert (bar.x == 23);
+               assert (bar.y == 42);
+               assert (bar.z == 67);
+       }
+}
diff --git a/vala/valagenieparser.vala b/vala/valagenieparser.vala
index 2b3537cf6..43ff863de 100644
--- a/vala/valagenieparser.vala
+++ b/vala/valagenieparser.vala
@@ -1179,8 +1179,16 @@ public class Vala.Genie.Parser : CodeVisitor {
                var begin = get_location ();
                string id = parse_identifier ();
                expect (TokenType.ASSIGN);
-               var expr = parse_expression ();
 
+               var inner = get_location ();
+               Expression expr;
+               try {
+                       // chained member initializer
+                       expr = parse_member_initializer ();
+               } catch {
+                       rollback (inner);
+                       expr = parse_expression ();
+               }
                return new MemberInitializer (id, expr, get_src (begin));
        }
 
diff --git a/vala/valamemberinitializer.vala b/vala/valamemberinitializer.vala
index 270e4204d..3f693120e 100644
--- a/vala/valamemberinitializer.vala
+++ b/vala/valamemberinitializer.vala
@@ -26,7 +26,7 @@ using GLib;
  * Represents a member initializer, i.e. an element of an object initializer, in
  * the source code.
  */
-public class Vala.MemberInitializer : CodeNode {
+public class Vala.MemberInitializer : Expression {
        /**
         * Member name.
         */
@@ -43,11 +43,6 @@ public class Vala.MemberInitializer : CodeNode {
                }
        }
 
-       /**
-        * The symbol this expression refers to.
-        */
-       public weak Symbol symbol_reference { get; set; }
-
        Expression _initializer;
 
        /**
@@ -64,6 +59,10 @@ public class Vala.MemberInitializer : CodeNode {
                this.name = name;
        }
 
+       public override bool is_pure () {
+               return false;
+       }
+
        public override void accept (CodeVisitor visitor) {
                initializer.accept (visitor);
        }
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index 1126288b8..ca2731258 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -507,7 +507,34 @@ public class Vala.ObjectCreationExpression : Expression, CallableExpression {
                        context.analyzer.check_type (type_reference);
                }
 
+               // Unwrap chained member initializers
                foreach (MemberInitializer init in get_object_initializer ()) {
+                       if (!(init.initializer is MemberInitializer)) {
+                               continue;
+                       }
+
+                       int index = object_initializer.index_of (init);
+                       object_initializer.remove_at (index);
+                       assert (index >= 0);
+
+                       unowned MemberInitializer? inner_mi = (MemberInitializer) init.initializer;
+                       while (inner_mi.initializer is MemberInitializer) {
+                               inner_mi = (MemberInitializer) inner_mi.initializer;
+                       }
+
+                       var local = new LocalVariable (null, get_temp_name (), inner_mi.initializer, 
inner_mi.initializer.source_reference);
+                       var decl = new DeclarationStatement (local, inner_mi.initializer.source_reference);
+                       decl.check (context);
+                       insert_statement (context.analyzer.insert_block, decl);
+
+                       do {
+                               var member_init = new MemberInitializer (inner_mi.name, new MemberAccess 
(null, local.name, inner_mi.source_reference), inner_mi.source_reference);
+                               object_initializer.insert (index++, member_init);
+                               inner_mi = inner_mi.parent_node as MemberInitializer;
+                       } while (inner_mi != null);
+               }
+               foreach (MemberInitializer init in get_object_initializer ()) {
+                       init.parent_node = this;
                        init.check (context);
                }
 
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 2c2db2d3a..7236d5c7b 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -1064,8 +1064,16 @@ public class Vala.Parser : CodeVisitor {
                var begin = get_location ();
                string id = parse_identifier ();
                expect (TokenType.ASSIGN);
-               var expr = parse_expression ();
 
+               var inner = get_location ();
+               Expression expr;
+               try {
+                       // chained member initializer
+                       expr = parse_member_initializer ();
+               } catch {
+                       rollback (inner);
+                       expr = parse_expression ();
+               }
                return new MemberInitializer (id, expr, get_src (begin));
        }
 


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