diff options
author | Rico Tzschichholz <ricotz@ubuntu.com> | 2020-09-30 08:41:05 +0200 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2020-10-18 22:41:42 +0200 |
commit | b3bdd54eb4451bfc3d0f7e69b18b2ae5dc081af4 (patch) | |
tree | 87c188dd02dca1d2a1da408e23af19ba8242ee61 | |
parent | b8bc5e2e44698cef18fa4378deafd737297fb65e (diff) | |
download | vala-wip/explicit-class-access.tar.gz |
WIP vala: Allow explicit access to class members using the "class" keywordwip/explicit-class-access
-rw-r--r-- | codegen/valaccodebasemodule.vala | 14 | ||||
-rw-r--r-- | codegen/valaccodememberaccessmodule.vala | 22 | ||||
-rw-r--r-- | codegen/valaccodemethodcallmodule.vala | 25 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/objects/class-access.vala | 44 | ||||
-rw-r--r-- | vala/Makefile.am | 1 | ||||
-rw-r--r-- | vala/valaclassaccess.vala | 82 | ||||
-rw-r--r-- | vala/valacodevisitor.vala | 8 | ||||
-rw-r--r-- | vala/valacodewriter.vala | 4 | ||||
-rw-r--r-- | vala/valamemberaccess.vala | 21 | ||||
-rw-r--r-- | 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 @@ -550,6 +550,14 @@ public abstract class Vala.CodeVisitor { } /** + * 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. * * @param expr a postfix expression 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)); |