[vala/wip/explicit-class-access: 12/12] WIP vala: Allow explicit access to class members using the "class" keyword




commit b3bdd54eb4451bfc3d0f7e69b18b2ae5dc081af4
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Wed Sep 30 08:41:05 2020 +0200

    WIP vala: Allow explicit access to class members using the "class" keyword

 codegen/valaccodebasemodule.vala         | 14 ++++++
 codegen/valaccodememberaccessmodule.vala | 22 ++-------
 codegen/valaccodemethodcallmodule.vala   | 25 ++--------
 tests/Makefile.am                        |  1 +
 tests/objects/class-access.vala          | 44 +++++++++++++++++
 vala/Makefile.am                         |  1 +
 vala/valaclassaccess.vala                | 82 ++++++++++++++++++++++++++++++++
 vala/valacodevisitor.vala                |  8 ++++
 vala/valacodewriter.vala                 |  4 ++
 vala/valamemberaccess.vala               | 21 +++++++-
 vala/valaparser.vala                     |  9 ++++
 11 files changed, 191 insertions(+), 40 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index b11992e17..638f41e4e 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -4448,6 +4448,20 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                }
        }
 
+       public override void visit_class_access (ClassAccess expr) {
+               CCodeExpression klass;
+               if (get_this_type () == null) {
+                       // Accessing the member from a static or class constructor
+                       klass = new CCodeIdentifier ("klass");
+               } else {
+                       // Accessing the member from within an instance method
+                       var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
+                       k.add_argument (get_this_cexpression ());
+                       klass = k;
+               }
+               set_cvalue (expr, klass);
+       }
+
        public override void visit_postfix_expression (PostfixExpression expr) {
                MemberAccess ma = find_property_access (expr.inner);
                if (ma != null) {
diff --git a/codegen/valaccodememberaccessmodule.vala b/codegen/valaccodememberaccessmodule.vala
index 3199ea24e..047748b3e 100644
--- a/codegen/valaccodememberaccessmodule.vala
+++ b/codegen/valaccodememberaccessmodule.vala
@@ -682,26 +682,10 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                                }
                        }
                } else if (field.binding == MemberBinding.CLASS) {
-                       var cl = (Class) field.parent_symbol;
-                       var cast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function 
(cl)));
+                       var klass = get_cvalue_ (instance);
 
-                       CCodeExpression klass;
-                       if (instance == null) {
-                               if (get_this_type () == null) {
-                                       // Accessing the field from a static or class constructor
-                                       klass = new CCodeIdentifier ("klass");
-                               } else {
-                                       // Accessing the field from within an instance method
-                                       var k = new CCodeFunctionCall (new CCodeIdentifier 
("G_OBJECT_GET_CLASS"));
-                                       k.add_argument (new CCodeIdentifier ("self"));
-                                       klass = k;
-                               }
-                       } else {
-                               // Accessing the field of an instance
-                               var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
-                               k.add_argument (get_cvalue_ (instance));
-                               klass = k;
-                       }
+                       unowned Class cl = (Class) field.parent_symbol;
+                       var cast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function 
(cl)));
                        cast.add_argument (klass);
 
                        if (field.access == SymbolAccessibility.PRIVATE) {
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index 2c5be10c3..36286ffe7 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -243,28 +243,13 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                                in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
                        }
                } else if (m != null && m.binding == MemberBinding.CLASS) {
-                       var cl = (Class) m.parent_symbol;
-                       var cast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function 
(cl)));
-
-                       CCodeExpression klass;
-                       if (ma.inner == null) {
-                               if (get_this_type () == null) {
-                                       // Accessing the method from a static or class constructor
-                                       klass = new CCodeIdentifier ("klass");
-                               } else {
-                                       // Accessing the method from within an instance method
-                                       var k = new CCodeFunctionCall (new CCodeIdentifier 
("G_OBJECT_GET_CLASS"));
-                                       k.add_argument (get_this_cexpression ());
-                                       klass = k;
-                               }
-                       } else {
-                               // Accessing the method of an instance
-                               var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
-                               k.add_argument (get_cvalue (ma.inner));
-                               klass = k;
-                       }
+                       assert (ma.inner is ClassAccess);
+                       var klass = get_cvalue (ma.inner);
 
+                       unowned Class cl = (Class) m.parent_symbol;
+                       var cast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function 
(cl)));
                        cast.add_argument (klass);
+
                        in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), cast);
                        out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), cast);
                }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3be19f407..d84f9d642 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -370,6 +370,7 @@ TESTS = \
        delegates/bug772204.test \
        delegates/bug792077.vala \
        objects/chainup.vala \
+       objects/class-access.vala \
        objects/class-ccode-cprefix.vala \
        objects/class_only.vala \
        objects/class-destroysinstance.vala \
diff --git a/tests/objects/class-access.vala b/tests/objects/class-access.vala
new file mode 100644
index 000000000..e3cda3764
--- /dev/null
+++ b/tests/objects/class-access.vala
@@ -0,0 +1,44 @@
+class Foo {
+       public class int foo = 42;
+
+       public class int get_foo () {
+               return 23;
+       }
+
+       public static void manam (TypeClass t) {
+               assert (t.get_type ().is_a (typeof (Foo)));
+       }
+}
+
+class Bar : Foo {
+       static construct {
+               assert (foo == 42);
+               class.foo = 4711;
+               assert (class.foo == 4711);
+               assert (class.get_foo () == 23);
+               //FIXME manam (class);
+       }
+
+       public Bar () {
+               assert (this.get_foo () == 42);
+               assert (get_foo () == 42);
+               assert (foo == 4711);
+               assert (class.foo == 4711);
+               assert (class.get_foo () == 23);
+               //FIXME manam (class);
+       }
+
+       public int get_foo () {
+               assert (foo == 4711);
+               assert (class.foo == 4711);
+               //FIXME manam (class);
+               return 42;
+       }
+}
+
+void main() {
+       var bar = new Bar ();
+
+       //FIXME assert (classof (Bar).foo == 4711);
+       //FIXME assert (classof (Bar).get_foo () == 23);
+}
diff --git a/vala/Makefile.am b/vala/Makefile.am
index 8a9badd4c..5dcc2766d 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -48,6 +48,7 @@ libvala_la_VALASOURCES = \
        valacatchclause.vala \
        valacharacterliteral.vala \
        valaclass.vala \
+       valaclassaccess.vala \
        valaclasstype.vala \
        valacodecontext.vala \
        valacodegenerator.vala \
diff --git a/vala/valaclassaccess.vala b/vala/valaclassaccess.vala
new file mode 100644
index 000000000..2e3bbc51c
--- /dev/null
+++ b/vala/valaclassaccess.vala
@@ -0,0 +1,82 @@
+/* valaclassaccess.vala
+ *
+ * Copyright (C) 2020  Rico Tzschichholz
+ *
+ * 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:
+ *     Rico Tzschichholz <ricotz ubuntu com>
+ */
+
+
+/**
+ * Represents an access to class member in the source code.
+ */
+public class Vala.ClassAccess : Expression {
+       /**
+        * Creates a new class access expression.
+        *
+        * @param source reference to source code
+        * @return       newly created class access expression
+        */
+       public ClassAccess (SourceReference? source = null) {
+               source_reference = source;
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               visitor.visit_class_access (this);
+
+               visitor.visit_expression (this);
+       }
+
+       public override string to_string () {
+               return "class";
+       }
+
+       public override bool is_pure () {
+               return true;
+       }
+
+       public override bool check (CodeContext context) {
+               if (checked) {
+                       return !error;
+               }
+
+               checked = true;
+
+               if (context.analyzer.current_class == null) {
+                       error = true;
+                       Report.error (source_reference, "Class access invalid outside of class");
+                       return false;
+               } else if (context.analyzer.current_class.is_compact) {
+                       error = true;
+                       Report.error (source_reference, "Class access invalid in compact class");
+                       return false;
+               } else {
+                       value_type = SemanticAnalyzer.get_data_type_for_symbol 
(context.analyzer.current_class);
+                       value_type.value_owned = false;
+               }
+
+               symbol_reference = value_type.type_symbol;
+
+               return !error;
+       }
+
+       public override void emit (CodeGenerator codegen) {
+               codegen.visit_class_access (this);
+
+               codegen.visit_expression (this);
+       }
+}
diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala
index f47f96349..fe71d4c4d 100644
--- a/vala/valacodevisitor.vala
+++ b/vala/valacodevisitor.vala
@@ -549,6 +549,14 @@ public abstract class Vala.CodeVisitor {
        public virtual void visit_base_access (BaseAccess expr) {
        }
 
+       /**
+        * Visit operation called for class access expressions.
+        *
+        * @param expr a class access expression
+        */
+       public virtual void visit_class_access (ClassAccess expr) {
+       }
+
        /**
         * Visit operation called for postfix expressions.
         *
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index 20415cbdd..a5a99cfa1 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1345,6 +1345,10 @@ public class Vala.CodeWriter : CodeVisitor {
                write_string ("base");
        }
 
+       public override void visit_class_access (ClassAccess expr) {
+               write_string ("class");
+       }
+
        public override void visit_postfix_expression (PostfixExpression expr) {
                expr.inner.accept (this);
                if (expr.increment) {
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index b1cc20ada..4a6bda128 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -402,6 +402,22 @@ public class Vala.MemberAccess : Expression {
                                                may_access_klass_members = true;
                                        }
                                }
+                       } else if (inner is ClassAccess) {
+                               unowned Class cl = (Class) inner.symbol_reference;
+
+                               while (cl != null) {
+                                       symbol_reference = cl.scope.lookup (member_name);
+                                       if (symbol_reference is Method && ((Method) symbol_reference).binding 
== MemberBinding.CLASS) {
+                                               may_access_klass_members = true;
+                                               break;
+                                       } else if (symbol_reference is Field && ((Field) 
symbol_reference).binding == MemberBinding.CLASS) {
+                                               may_access_klass_members = true;
+                                               break;
+                                       } else {
+                                               symbol_reference = null;
+                                       }
+                                       cl = cl.base_class;
+                               }
                        }
 
                        if (inner is MemberAccess && inner.symbol_reference is TypeParameter) {
@@ -916,12 +932,15 @@ public class Vala.MemberAccess : Expression {
                                value_type.value_owned = target_type.value_owned;
                        }
                } else {
-                       // implicit this access
+                       // implicit this or class access
                        if (instance && inner == null) {
                                inner = new MemberAccess (null, "this", source_reference);
                                inner.value_type = this_parameter.variable_type.copy ();
                                inner.value_type.value_owned = false;
                                inner.symbol_reference = this_parameter;
+                       } else if (klass && inner == null) {
+                               inner = new ClassAccess (source_reference);
+                               inner.check (context);
                        } else {
                                check_lvalue_access ();
                        }
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 74cf0f2f4..55b3afb04 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -690,6 +690,9 @@ public class Vala.Parser : CodeVisitor {
                case TokenType.BASE:
                        expr = parse_base_access ();
                        break;
+               case TokenType.CLASS:
+                       expr = parse_class_access ();
+                       break;
                case TokenType.NEW:
                        expr = parse_object_or_array_creation_expression ();
                        break;
@@ -913,6 +916,12 @@ public class Vala.Parser : CodeVisitor {
                return new BaseAccess (get_src (begin));
        }
 
+       Expression parse_class_access () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.CLASS);
+               return new ClassAccess (get_src (begin));
+       }
+
        Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError 
{
                expect (TokenType.OP_INC);
                return new PostfixExpression (inner, true, get_src (begin));


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