Enum Resolution - HimxhMC/HimDSL GitHub Wiki
枚举解析机制 / Enum Resolution
从一句代码说起 / A Small Piece of Code
var m = Material.DIAMOND;
HimDSL 怎么知道 Material.DIAMOND 是"枚举值",而不是"字段 Material 的字段 DIAMOND"?
How does HimDSL know Material.DIAMOND is an enum value, not a "field DIAMOND of variable Material"?
规则是最长匹配:从代码文本里尽可能多地收集连续的 Name.Name.Name 段,然后依次尝试:
The rule is longest match: gather as many consecutive Name.Name.Name segments as possible, then try:
-
作为枚举路径(段数 ≥ 2)。
-
作为类路径(段数 ≥ 1)。
-
As an enum path (segments ≥ 2).
-
As a class path (segments ≥ 1).
成功即停,不再尝试更短的组合。
Stop on success — shorter combinations are not tried.
最长匹配的例子 / Longest Match in Action
Material.DIAMOND
段:["Material", "DIAMOND"]
- 尝试枚举路径
Material.DIAMOND→ 找到 → 返回枚举值。
org.bukkit.Material.DIAMOND
段:["org", "bukkit", "Material", "DIAMOND"]
- 尝试
org.bukkit.Material.DIAMOND→ 找到 → 返回枚举值。 - 不会再尝试
bukkit.Material.DIAMOND或Material.DIAMOND。
Color.RED
段:["Color", "RED"]
- 尝试
Color.RED。如果Color是用户枚举,返回用户枚举值。 - 如果
Color是 Java 类,且RED是它的枚举常量,返回 Java 枚举值。 - 都没找到 → 失败。
方法调用不参与匹配 / Method Calls Are Not Enumerated
Material.values()
段扫描会停在 .values 之前——因为 values 后面紧跟着 (,说明它是方法名,不是枚举段。
The scan stops before .values — because values is followed by (, marking it as a method, not an enum segment.
解析过程:
The resolution:
-
段 =
["Material"](只有一段)。 -
尝试枚举路径:段数不足 → 跳过。
-
尝试类路径:
Material→ 找到 → 返回类对象。 -
后续
.values()调用静态方法。 -
Segments =
["Material"](one only). -
Enum path: too few → skip.
-
Class path:
Material→ resolved → return class object. -
Subsequent
.values()calls the static method.
关键规则:后跟 ( 的段不纳入枚举路径。
Key rule: a segment followed by ( is not part of an enum path.
用户枚举与 Java 枚举 / User vs Java Enums
两种枚举共存,解析规则相同:
Both kinds coexist with the same resolution:
enum Color { RED, GREEN, BLUE };
Color.RED // 用户枚举
Material.DIAMOND // Java 枚举
两段式的优先级:先查用户枚举,再查 Java 类。
Two-segment priority: user enums are checked before Java classes.
如果用户定义了 enum Material { DIAMOND },那么 Material.DIAMOND 会解析为用户枚举而不是 Java 的 Material.DIAMOND。这是个罕见的坑——不要给用户枚举取和 Java 类相同的名字。
If a user defines enum Material { DIAMOND }, then Material.DIAMOND resolves to the user enum, not Java's. A rare trap — do not name user enums after Java classes.
与变量的交互 / Interaction with Variables
如果 Material 是脚本里的一个变量,会怎样?
If Material is a script variable, what happens?
Material.DIAMOND // Material 是变量名时……
解析器先检查 Material 是否在当前作用域内已声明:
The parser first checks whether Material is a declared variable in scope:
-
是变量 → 当作
变量.字段处理,不尝试枚举。 -
不是变量 → 走枚举路径解析。
-
Is a variable → treat as
var.field, no enum resolution. -
Not a variable → proceed with enum resolution.
这就意味着:
This implies:
enum Material { DIAMOND };
var Material = someObject;
var x = Material.DIAMOND; // 用的是变量,不是枚举
变量的优先级高于枚举。给变量取和类名相同的名字能覆盖类解析,但会让代码难以理解。避免这样做。
Variables take priority over enums. Naming a variable after a class shadows the class, but hurts readability. Avoid.
常见错误 / Common Mistakes
错误一:给枚举起冲突名
enum Material { STONE, DIAMOND }; // ✗ 和 Java 的 Material 冲突
用户枚举不要用 Java 类的名字。取个独一无二的:MyMaterial、GameItem。
错误二:把静态方法当枚举路径
Material.DIAMOND.name() // ✓ 先解析枚举再调方法
Material.values // ✗ 这是个方法,不是字段,会失败
想拿到所有枚举值,写 Material.values()(带括号)。
错误三:变量遮蔽类名
var Diamond = Material.DIAMOND; // 变量名和枚举常量同名
// 后面用 Diamond 时,拿到的是变量,不是枚举常量
变量名不要和枚举常量名相同,会造成混淆。
Mistake 1: Conflicting enum names
Do not name user enums after Java classes.
Mistake 2: Static methods as enum paths
Material.values (without parentheses) fails; Material.values() works.
Mistake 3: Variables shadowing class names
Avoid naming variables after classes or enum constants.
什么时候需要在意 / When You Need This
日常脚本 99% 情况下不需要。写 Material.DIAMOND 就管用,不用想解析过程。
99% of daily scripts never need this. Material.DIAMOND just works.
遇到下列情况回来查这章:
Come back when:
-
枚举引用报"找不到"。
-
一个表达式的结果不符合直觉(拿到了变量而不是枚举)。
-
自己定义枚举和 Java 类重名。
-
An enum reference reports "not found".
-
An expression behaves unintuitively (variable instead of enum).
-
A user enum shares a name with a Java class.
小结 / Summary
-
最长匹配:尽可能收集连续
Name.Name段。 -
后跟
(的段不参与枚举匹配。 -
优先级:变量 > 用户枚举 > Java 类。
-
用户枚举不要用 Java 类名。
-
日常不需要关心;出错时回来查。
-
Longest match: collect as many
Name.Namesegments as possible. -
Segments followed by
(are excluded. -
Priority: variables > user enums > Java classes.
-
Never name user enums after Java classes.
-
Daily scripts ignore this; come back when something misfires.
下一步 / Next Steps
下一章 [作用域与闭包 / Scopes-and-Closures] 讲变量在哪里可见,lambda 怎么捕获它们。
Next, [作用域与闭包 / Scopes-and-Closures] covers where variables are visible and how lambdas capture them.