Skip to content

Commit

Permalink
Merge pull request #54 from xp-framework/feature/asymmetric-visibility
Browse files Browse the repository at this point in the history
Add syntactic support for asymmetric visibility
  • Loading branch information
thekid authored Aug 26, 2024
2 parents 8375c86 + e5e93ed commit aa454ca
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 11 deletions.
44 changes: 33 additions & 11 deletions src/main/php/lang/ast/syntax/PHP.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -1476,8 +1476,35 @@ private function annotations($parse, $context) {
return $annotations;
}

private function modifier($parse) {
static $hooks= ['set' => true];

$modifier= $parse->token->value;
$parse->forward();

if ('(' === $parse->token->value) {
$token= $parse->token;
$parse->expecting('(', 'modifiers');

if (isset($hooks[$parse->token->value])) {
$modifier.= '('.$parse->token->value.')';
$parse->forward();
$parse->expecting(')', 'modifiers');
} else {
array_unshift($parse->queue, $parse->token);
$parse->token= $token;
}
}
return $modifier;
}

private function parameters($parse) {
static $promotion= ['private' => true, 'protected' => true, 'public' => true];
static $promotion= [
'private' => true,
'protected' => true,
'public' => true,
'readonly' => true,
];

$parameters= [];
while (')' !== $parse->token->value) {
Expand All @@ -1490,14 +1517,10 @@ private function parameters($parse) {

$line= $parse->token->line;
if ('name' === $parse->token->kind && isset($promotion[$parse->token->value])) {
$promote= $parse->token->value;
$parse->forward();

// It would be better to use an array for promote, but this way we keep BC
if ('readonly' === $parse->token->value) {
$promote.= ' readonly';
$parse->forward();
}
$promote= [];
do {
$promote[]= $this->modifier($parse);
} while (isset($promotion[$parse->token->value]));
} else {
$promote= null;
}
Expand Down Expand Up @@ -1566,8 +1589,7 @@ public function typeBody($parse) {
$meta= [];
while ('}' !== $parse->token->value) {
if (isset($modifier[$parse->token->value])) {
$modifiers[]= $parse->token->value;
$parse->forward();
$modifiers[]= $this->modifier($parse);
} else if ($f= $this->body[$parse->token->value] ?? $this->body['@'.$parse->token->kind] ?? null) {
$f($parse, $body, $meta, $modifiers);
$modifiers= [];
Expand Down
17 changes: 17 additions & 0 deletions src/test/php/lang/ast/unittest/parse/MembersTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,21 @@ public function typed_constants() {

$this->assertParsed([$class], 'class A { const int T = 1, S = 2, string I = "i"; }');
}

#[Test]
public function asymmetric_property() {
$class= new ClassDeclaration([], new IsValue('\\A'), null, [], [], null, null, self::LINE);
$class->declare(new Property(['public', 'private(set)'], 'a', new Type('int'), null, null, null, self::LINE));

$this->assertParsed([$class], 'class A { public private(set) int $a; }');
}

#[Test]
public function asymmetric_property_as_constructor_argument() {
$params= [new Parameter('a', new IsLiteral('int'), null, false, false, ['private(set)'], null, null, self::LINE)];
$class= new ClassDeclaration([], new IsValue('\\A'), null, [], [], null, null, self::LINE);
$class->declare(new Method(['public'], '__construct', new Signature($params, null, false, self::LINE), [], null, null, self::LINE));

$this->assertParsed([$class], 'class A { public function __construct(private(set) int $a) { } }');
}
}

0 comments on commit aa454ca

Please sign in to comment.