CommandRegistry 注册时,
它会把这一段当作 command 解析,而不是普通标识符/函数调用。
Fluxon 默认不内置任何 command:是否存在、叫什么名字、怎么解析参数,都由宿主在启动时注册决定。
适用场景
- 你希望写成 DSL 风格的语句:
give-item "diamond" 64。 - 你需要自定义参数语法(不仅是
func(a, b)这种固定形态)。 - 你想把宿主侧的“指令/动作”封装成脚本表达式并返回结果。
与其他机制的区别
组成与执行流程
执行大致流程:
- Parser 读到
IDENTIFIER,CommandSyntaxMacro发现已注册同名 command。 - 先消费 command 名称 token,再调用
CommandParser#parse(...)解析后续参数。 - 解析结果与
CommandExecutor一起被封装进CommandExpression。 - Interpreter 执行到该节点时,直接调用 executor 并返回结果。
注册与隔离
使用全局主注册表(最常见)
在应用启动时注册即可(建议注册阶段单线程):为沙箱/多租户使用独立注册表
如果你需要“每份脚本一套 command 集合”,可以创建独立实例并放到CompilationContext:
如果你也自定义了
SyntaxMacroRegistry,记得把 CommandSyntaxMacro 放进去;
否则即使 registry 有 command,解析器也不会命中。最小示例:实现 give-item
这个 command 语法为:give-item <itemName> <amount>。
它解析物品名称和数量,并返回操作结果。
注意事项
- 命名规则:command 名称是标识符(
IDENTIFIER),允许包含-(例如give-item)。 - 命名冲突:command 的匹配发生在“标识符兜底”之前, 如果你注册了与函数/变量同名的 command,会改变解析结果。
- 解析要消费完整:
CommandParser必须把它负责的 token 消费完, 否则后续解析会报位置看似不相关的错误。 - 错误要可定位:
- 解析阶段用
ParseException(通过parser.consume(..., "message")自动生成)。 - 运行阶段建议抛出自定义
FluxonRuntimeError子类,以获得 SourceTrace。
- 解析阶段用