-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
Suggestion
Support visibility modifiers on types:
public
- type can be used anywhereprotected
- type can only be used inside the same namespace and sub-namespacesprivate
- type can only be used inside the same namespace
See https://externals.io/message/127341
POC (syntactical support)
Diff for xp-framework/ast
:
diff --git a/src/main/php/lang/ast/syntax/PHP.class.php b/src/main/php/lang/ast/syntax/PHP.class.php
index 80186a6..9fcbd16 100755
--- a/src/main/php/lang/ast/syntax/PHP.class.php
+++ b/src/main/php/lang/ast/syntax/PHP.class.php
@@ -863,6 +863,24 @@ class PHP extends Language {
return $type;
});
+ $this->stmt('public', function($parse, $token) {
+ $type= $this->statement($parse);
+ $type->modifiers[]= 'public';
+ return $type;
+ });
+
+ $this->stmt('protected', function($parse, $token) {
+ $type= $this->statement($parse);
+ $type->modifiers[]= 'protected';
+ return $type;
+ });
+
+ $this->stmt('private', function($parse, $token) {
+ $type= $this->statement($parse);
+ $type->modifiers[]= 'private';
+ return $type;
+ });
+
$this->stmt('#[', function($parse, $token) {
$annotations= $this->annotations($parse, 'annotations');
return $this->statement($parse)->annotate($annotations);
diff --git a/src/test/php/lang/ast/unittest/parse/TypesTest.class.php b/src/test/php/lang/ast/unittest/parse/TypesTest.class.php
index cafb2cb..7277e73 100755
--- a/src/test/php/lang/ast/unittest/parse/TypesTest.class.php
+++ b/src/test/php/lang/ast/unittest/parse/TypesTest.class.php
@@ -12,7 +12,7 @@ use lang\ast\nodes\{
Literal
};
use lang\ast\types\IsValue;
-use test\{Assert, Expect, Test};
+use test\{Assert, Expect, Test, Values};
class TypesTest extends ParseTest {
@@ -64,6 +64,22 @@ class TypesTest extends ParseTest {
);
}
+ #[Test, Values(['public', 'private', 'protected'])]
+ public function class_with_visibility($modifier) {
+ $this->assertParsed(
+ [new ClassDeclaration([$modifier], new IsValue('\\A'), null, [], [], null, null, self::LINE)],
+ $modifier.' class A { }'
+ );
+ }
+
+ #[Test]
+ public function public_abstract_class() {
+ $this->assertParsed(
+ [new ClassDeclaration(['abstract', 'public'], new IsValue('\\A'), null, [], [], null, null, self::LINE)],
+ 'public abstract class A { }'
+ );
+ }
+
#[Test]
public function empty_interface() {
$this->assertParsed(
Implemetation idea: Name mangling
Emit non-public classes with namespace name so they aren't "visible" to the outside:
namespace com\example;
// Emit this as `__com_example_Parser`
private class Parser { }
When encountering type names, check for private and protected names if the type doesn't exist:
namespace com\example;
class Subject {
public function parse($input) {
return new Parser($input); // Emitted as __com_example_Parser
}
}
This would need some further adjustments to the reflection API, though!
Implemetation idea: Compiler checks
When encountering type names, check xp::$meta
for class visibility, and yield errors accordingly:
namespace de\thekid;
use com\example\Parser;
class Subject {
public function parse($input) {
return new Parser($input); // Error: Cannot use private class "com.example.Parser" in "de.thekid"
}
}
Implemetation idea: Unchecked
Only store visibility modifiers inside xp::$meta
but do not check it during compilation.