summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRico Tzschichholz <ricotz@ubuntu.com>2020-09-30 08:41:05 +0200
committerRico Tzschichholz <ricotz@ubuntu.com>2020-10-18 22:41:42 +0200
commitb3bdd54eb4451bfc3d0f7e69b18b2ae5dc081af4 (patch)
tree87c188dd02dca1d2a1da408e23af19ba8242ee61
parentb8bc5e2e44698cef18fa4378deafd737297fb65e (diff)
downloadvala-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.vala14
-rw-r--r--codegen/valaccodememberaccessmodule.vala22
-rw-r--r--codegen/valaccodemethodcallmodule.vala25
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/objects/class-access.vala44
-rw-r--r--vala/Makefile.am1
-rw-r--r--vala/valaclassaccess.vala82
-rw-r--r--vala/valacodevisitor.vala8
-rw-r--r--vala/valacodewriter.vala4
-rw-r--r--vala/valamemberaccess.vala21
-rw-r--r--vala/valaparser.vala9
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));