From 26bdf5eb590f2b39c9134fe504fe1227c3573756 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 12 Jun 2026 18:12:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(enum):=20=E6=94=AF=E6=8C=81=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE=E7=B1=BB=E5=9E=8B=E8=A7=A3=E6=9E=90=E5=92=8C=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了枚举类型的语法解析功能 - 实现了对带值枚举(backed enums)的支持 - 添加了枚举案例值的存储和访问机制 - 支持枚举类型的运行时对象处理 - 完善了枚举常量数组的生成逻辑 - 新增了多个枚举相关的测试用例 --- src/Php/Entity/ClassDef.php | 11 ++++++++++ src/Php/Preprocessor.php | 6 ++++++ src/Php/Translator.php | 11 ++++++++++ tests/aot/enum/3.phpt | 41 +++++++++++++++++++++++++++++++++++++ tests/aot/enum/4.phpt | 30 +++++++++++++++++++++++++++ tests/aot/enum/5.phpt | 31 ++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+) create mode 100644 tests/aot/enum/3.phpt create mode 100644 tests/aot/enum/4.phpt create mode 100644 tests/aot/enum/5.phpt diff --git a/src/Php/Entity/ClassDef.php b/src/Php/Entity/ClassDef.php index 9af717da..1698bead 100644 --- a/src/Php/Entity/ClassDef.php +++ b/src/Php/Entity/ClassDef.php @@ -32,6 +32,17 @@ class ClassDef extends ClassLikeDef public string $extends = ''; public bool $requireCtor = false; public bool $enum = false; + + /** + * Backing type for backed enums ('int' or 'string'), null for pure enums. + */ + public ?string $enumBackingType = null; + + /** + * Enum cases: case name => backing value (int/string for backed enums, null for pure enums). + * @var array + */ + public array $enumCases = []; public ?Trait_ $trait = null; /** diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index f2725fd6..39e46f17 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -438,6 +438,9 @@ class Preprocessor extends CompilerBase if ($class instanceof Node\Stmt\Enum_) { $this->classDef->enum = true; + if ($class->scalarType !== null) { + $this->classDef->enumBackingType = $class->scalarType->name; + } } if (!$class instanceof Node\Stmt\Trait_) { $this->classDef->implements = $this->parseImplements($class->implements); @@ -464,7 +467,10 @@ class Preprocessor extends CompilerBase $this->prepareTraitUse($v); break; case 'Stmt_Nop': + break; case 'Stmt_EnumCase': + $caseName = $this->parseIdentifier($v->name); + $this->classDef->enumCases[$caseName] = $v->expr?->value; break; case 'Stmt_ClassMethod': $this->prepareClassMethod($v, $class); diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 82c5c432..bbb79438 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -1518,6 +1518,17 @@ CODE; return $this->genCValue(constant($constName)); } } + // Resolve enum case references. Enum cases are runtime objects; their + // actual values in class constant arrays are set at runtime by + // genClassArrayConstants() via php::getEnumCase(). Return the backing + // value as a placeholder so gen_stub.php's ConstExprEvaluator can complete. + if ($this->hasClass($class)) { + $classDef = $this->getClass($class); + if ($classDef->enum && array_key_exists($name, $classDef->enumCases)) { + $caseValue = $classDef->enumCases[$name]; + return $this->genCValue($caseValue ?? $name); + } + } $this->fatalError($expr, "Class constant `{$class}::{$name}` not found"); } diff --git a/tests/aot/enum/3.phpt b/tests/aot/enum/3.phpt new file mode 100644 index 00000000..773b2b53 --- /dev/null +++ b/tests/aot/enum/3.phpt @@ -0,0 +1,41 @@ +--TEST-- +enum 2 +--FILE-- + ['d' => '', 't' => T::S], + '2' => ['d' => 1, 't' => T::I], + '3' => ['d' => 123, 't' => T::S], + ]; + + public static function E(): array + { + return self::F; + } +} + +function main() +{ + foreach (TestSpa::E() as $n => $f) { + + $ok = match ($f['t']) { + T::I => is_int($f['d']), + T::S => is_string($f['d']), + }; + + echo $ok? " pass {$n} => [{$f['d']}, {$f['t']->value}]\n": " fail {$n} 元组非法\n"; + } +} +?> +--EXPECT-- +pass 1 => [, string] + pass 2 => [1, int] + fail 3 元组非法 \ No newline at end of file diff --git a/tests/aot/enum/4.phpt b/tests/aot/enum/4.phpt new file mode 100644 index 00000000..9436eb43 --- /dev/null +++ b/tests/aot/enum/4.phpt @@ -0,0 +1,30 @@ +--TEST-- +enum 2 +--FILE-- + +--EXPECT-- +array(2) { + [0]=> + enum(TestEnum::FOO) + [1]=> + enum(TestEnum::BAR) +} \ No newline at end of file diff --git a/tests/aot/enum/5.phpt b/tests/aot/enum/5.phpt new file mode 100644 index 00000000..7e30725a --- /dev/null +++ b/tests/aot/enum/5.phpt @@ -0,0 +1,31 @@ +--TEST-- +enum 2 +--FILE-- +value); +} +?> +--EXPECT-- +array(2) { + [0]=> + enum(TestEnum::FOO) + [1]=> + enum(TestEnum::BAR) +} +enum(TestEnum::FOO) +string(3) "foo" \ No newline at end of file