[vala/staging] vala: Properly parse and handle chained initialization of members
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/staging] vala: Properly parse and handle chained initialization of members
- Date: Tue, 16 Feb 2021 21:57:38 +0000 (UTC)
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]