Skip to content

Commit aca3aad

Browse files
committed
Move native enum support detection to types
1 parent 0503bde commit aca3aad

File tree

5 files changed

+38
-74
lines changed

5 files changed

+38
-74
lines changed

src/main/php/lang/ast/emit/PHP81.class.php

Lines changed: 3 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php namespace lang\ast\emit;
22

33
use lang\ast\Node;
4-
use lang\ast\nodes\{Literal, Variable};
4+
use lang\ast\types\Type;
55
use lang\ast\types\{IsUnion, IsFunction, IsArray, IsMap, IsNullable, IsValue, IsLiteral};
66

77
/**
@@ -12,12 +12,6 @@
1212
class PHP81 extends PHP {
1313
use RewriteBlockLambdaExpressions;
1414

15-
private static $ENUMS;
16-
17-
static function __static() {
18-
self::$ENUMS= class_exists(\ReflectionEnum::class, false); // TODO remove once enum PR is merged
19-
}
20-
2115
/** Sets up type => literal mappings */
2216
public function __construct() {
2317
$this->literals= [
@@ -38,39 +32,6 @@ public function __construct() {
3832
];
3933
}
4034

41-
/**
42-
* Returns whether a given node is a constant expression:
43-
*
44-
* - Any literal
45-
* - Arrays where all members are literals
46-
* - Scope expressions with literal members (self::class, T::const)
47-
* - Binary expression where left- and right hand side are literals
48-
*
49-
* @see https://wiki.php.net/rfc/const_scalar_exprs
50-
* @param lang.ast.Result $result
51-
* @param lang.ast.Node $node
52-
* @return bool
53-
*/
54-
protected function isConstant($result, $node) {
55-
if ($node instanceof Literal) {
56-
return true;
57-
} else if ($node instanceof ArrayLiteral) {
58-
foreach ($node->values as $node) {
59-
if (!$this->isConstant($result, $node)) return false;
60-
}
61-
return true;
62-
} else if ($node instanceof ScopeExpression) {
63-
return (
64-
$node->member instanceof Literal &&
65-
is_string($node->type) &&
66-
!$result->lookup($node->type)->rewriteEnumCase($node->member->expression, self::$ENUMS)
67-
);
68-
} else if ($node instanceof BinaryExpression) {
69-
return $this->isConstant($result, $node->left) && $this->isConstant($result, $node->right);
70-
}
71-
return false;
72-
}
73-
7435
protected function emitArguments($result, $arguments) {
7536
$i= 0;
7637
foreach ($arguments as $name => $argument) {
@@ -80,28 +41,8 @@ protected function emitArguments($result, $arguments) {
8041
}
8142
}
8243

83-
protected function emitScope($result, $scope) {
84-
if ($scope->type instanceof Variable) {
85-
$this->emitOne($result, $scope->type);
86-
$result->out->write('::');
87-
$this->emitOne($result, $scope->member);
88-
} else if ($scope->type instanceof Node) {
89-
$t= $result->temp();
90-
$result->out->write('('.$t.'=');
91-
$this->emitOne($result, $scope->type);
92-
$result->out->write(')?'.$t.'::');
93-
$this->emitOne($result, $scope->member);
94-
$result->out->write(':null');
95-
} else if ($scope->member instanceof Literal && $result->lookup($scope->type)->rewriteEnumCase($scope->member->expression, self::$ENUMS)) {
96-
$result->out->write($scope->type.'::$'.$scope->member->expression);
97-
} else {
98-
$result->out->write($scope->type.'::');
99-
$this->emitOne($result, $scope->member);
100-
}
101-
}
102-
10344
protected function emitEnumCase($result, $case) {
104-
if (self::$ENUMS) {
45+
if (Type::$ENUMS) {
10546
$result->out->write('case '.$case->name);
10647
if ($case->expression) {
10748
$result->out->write('=');
@@ -114,7 +55,7 @@ protected function emitEnumCase($result, $case) {
11455
}
11556

11657
protected function emitEnum($result, $enum) {
117-
if (self::$ENUMS) {
58+
if (Type::$ENUMS) {
11859
array_unshift($result->type, $enum);
11960
array_unshift($result->meta, []);
12061
$result->locals= [[], []];

src/main/php/lang/ast/types/Declaration.class.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
use lang\ast\nodes\{EnumCase, Property};
44

5-
class Declaration implements Type {
5+
class Declaration extends Type {
66
private $type, $result;
77

8+
static function __static() { }
9+
810
/**
911
* @param lang.ast.nodes.TypeDeclaration $type
1012
* @param lang.ast.Result $result
@@ -21,11 +23,10 @@ public function name() { return ltrim($this->type->name, '\\'); }
2123
* Returns whether a given member is an enum case
2224
*
2325
* @param string $member
24-
* @param bool $native Whether native enum support exists
2526
* @return bool
2627
*/
27-
public function rewriteEnumCase($member, $native= false) {
28-
if (!$native && 'enum' === $this->type->kind) {
28+
public function rewriteEnumCase($member) {
29+
if (!self::$ENUMS && 'enum' === $this->type->kind) {
2930
return ($this->type->body[$member] ?? null) instanceof EnumCase;
3031
} else if ('class' === $this->type->kind && '\\lang\\Enum' === $this->type->parent) {
3132
return ($this->type->body['$'.$member] ?? null) instanceof Property;

src/main/php/lang/ast/types/Reflection.class.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
use lang\{Enum, ClassNotFoundException};
44

5-
class Reflection implements Type {
5+
class Reflection extends Type {
66
private $reflect;
77

8+
static function __static() { }
9+
810
/** @param string $type */
911
public function __construct($type) {
1012
try {
@@ -21,13 +23,12 @@ public function name() { return $this->reflect->name; }
2123
* Returns whether a given member is an enum case
2224
*
2325
* @param string $member
24-
* @param bool $native Whether enums are natively supported
2526
* @return bool
2627
*/
27-
public function rewriteEnumCase($member, $native= false) {
28+
public function rewriteEnumCase($member) {
2829
if ($this->reflect->isSubclassOf(Enum::class)) {
2930
return $this->reflect->getStaticPropertyValue($member, null) instanceof Enum;
30-
} else if (!$native && $this->reflect->isSubclassOf(\UnitEnum::class)) {
31+
} else if (!self::$ENUMS && $this->reflect->isSubclassOf(\UnitEnum::class)) {
3132
$value= $this->reflect->getConstant($member) ?: $this->reflect->getStaticPropertyValue($member, null);
3233
return $value instanceof \UnitEnum;
3334
}
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
<?php namespace lang\ast\types;
22

3-
interface Type {
3+
abstract class Type {
4+
public static $ENUMS;
5+
6+
static function __static() {
7+
self::$ENUMS= class_exists(\ReflectionEnum::class, false); // TODO remove once enum PR is merged
8+
}
49

510
/** @return string */
6-
public function name();
11+
public abstract function name();
712

813
/**
914
* Returns whether a given member is an enum case
1015
*
1116
* @param string $member
12-
* @param bool $native Whether native enum support exists
1317
* @return bool
1418
*/
15-
public function rewriteEnumCase($member, $native= false);
19+
public abstract function rewriteEnumCase($member);
1620
}

src/test/php/lang/ast/unittest/emit/EnumTest.class.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@ public function cases_method() {
3737
);
3838
}
3939

40+
#[Test]
41+
public function cases_method_does_not_yield_constants() {
42+
$t= $this->type('enum <T> {
43+
case Hearts;
44+
case Diamonds;
45+
case Clubs;
46+
case Spades;
47+
48+
const COLORS = ["red", "black"];
49+
}');
50+
51+
Assert::equals(
52+
['Hearts', 'Diamonds', 'Clubs', 'Spades'],
53+
array_map(function($suit) { return $suit->name; }, $t->getMethod('cases')->invoke(null))
54+
);
55+
}
56+
4057
#[Test]
4158
public function used_as_parameter_default() {
4259
$t= $this->type('enum <T> {

0 commit comments

Comments
 (0)