跳到主要内容

条件表达式求值器

条件表达式求值器是一个轻量级的逻辑表达式计算工具,专为配置文件中的条件判断场景设计。

设计初衷

在配置文件中经常需要让用户自己进行参数判断,例如 &amount >= 10。使用重量级脚本引擎显得笨重,而 Kether 的语法对于简单条件判断又显得过于复杂。因此,条件表达式求值器应运而生。

核心特点:

  • 轻量级实现,基于双栈算法
  • 支持逻辑运算和比较运算
  • 支持变量替换
  • 简洁的语法规则

基础用法

import top.maplex.arim.Arim

// 基本比较运算
Arim.evaluator.evaluate("1 > 2") // false
Arim.evaluator.evaluate("5 >= 3") // true

// 逻辑运算
Arim.evaluator.evaluate("5 > 3 && 2 < 10") // true

// 使用变量
Arim.evaluator.evaluate("a < 2", "a" to 5) // false

// 使用 Map 传递多个变量
Arim.evaluator.evaluate(
"level >= 10 && money > 1000",
mapOf("level" to 15, "money" to 1500)
) // true

语法规则

必须使用空格分隔

重要: 表达式中的每个元素(数字、字符串、运算符、括号)都必须用空格分隔。

// ✅ 正确写法
Arim.evaluator.evaluate("var > 5 && var < 10")
Arim.evaluator.evaluate("( 5 > 3 || 2 < 1 ) && 'a' != 'b'")

// ❌ 错误写法(缺少空格)
Arim.evaluator.evaluate("var>5&&var<10") // 解析错误
性能考虑

空格分隔是对性能的让步,使用空格可以简化解析逻辑,符合轻量级设计的初衷。

字符串必须加引号

字符串值必须用单引号 ' 或双引号 " 包围:

// ✅ 正确
Arim.evaluator.evaluate("name == 'John'", "name" to "枫溪")

// ❌ 错误
Arim.evaluator.evaluate("name == John") // 解析错误

变量无需加引号

// 变量在表达式中直接使用
Arim.evaluator.evaluate("level >= 10", "level" to 15)
Arim.evaluator.evaluate("name == 'Admin'", "name" to "Admin")

支持的运算符

比较运算符

运算符说明优先级示例
>大于25 > 3true
<小于22 < 10true
>=大于等于25 >= 5true
<=小于等于23 <= 5true
==等于210 == 10true
!=不等于25 != 3true

逻辑运算符

运算符说明优先级示例
&&逻辑与1true && truetrue
||逻辑或1true || falsetrue

括号

符号说明优先级
(左括号0
)右括号0

方法签名

evaluate - 无变量版本

fun evaluate(expression: String): Boolean

示例:

val result = Arim.evaluator.evaluate("10 > 5 && 3 < 7")

evaluate - 可变参数版本

fun evaluate(expression: String, vararg variable: Pair<String, Any>): Boolean

示例:

val result = Arim.evaluator.evaluate(
"level >= minLevel && score > minScore",
"level" to 10,
"minLevel" to 5,
"score" to 100,
"minScore" to 50
)

evaluate - Map 参数版本

fun evaluate(expression: String, variable: Map<String, Any>): Boolean

示例:

val variables = mapOf(
"level" to 10,
"minLevel" to 5
)
val result = Arim.evaluator.evaluate("level >= minLevel", variables)

实际应用示例

等级与金币检查

fun checkRequirements(player: Player): Boolean {
val level = player.level
val money = economy.getBalance(player)

return Arim.evaluator.evaluate(
"level >= 10 && money >= 1000",
mapOf("level" to level, "money" to money)
)
}

配置文件条件

rewards:
diamond:
item: DIAMOND
amount: 10
condition: "level >= 10 && vip == 'true'"
fun giveReward(player: Player, condition: String) {
val variables = mapOf(
"level" to player.level,
"vip" to hasVIP(player).toString()
)

if (Arim.evaluator.evaluate(condition, variables)) {
// 给予奖励
}
}

多条件组合判断

fun canEnterDungeon(player: Player): Boolean {
val level = player.level
val health = player.health
val hasKey = player.inventory.contains(Material.TRIPWIRE_HOOK)

// 复杂条件: (等级>=20 或 有钥匙) 且 生命值>10
return Arim.evaluator.evaluate(
"( level >= 20 || hasKey == 'true' ) && health > 10",
mapOf(
"level" to level,
"hasKey" to hasKey.toString(),
"health" to health
)
)
}

常见问题

为什么必须使用空格分隔?

空格分隔是性能和简洁性的权衡。使用空格可以简化词法分析,避免复杂的正则表达式或状态机,保持代码轻量。如果需要更复杂的语法,建议使用 Kether 或其他脚本引擎。

支持哪些数据类型?

目前支持两种类型:

  • 数字: 所有数字会被解析为 Double 类型
  • 字符串: 必须用引号包围的文本

表达式出错会抛出异常吗?

是的,格式错误时会抛出 IllegalArgumentException。建议添加异常处理:

try {
val result = Arim.evaluator.evaluate(expression, variables)
// 处理结果
} catch (e: IllegalArgumentException) {
logger.warning("条件表达式错误: ${e.message}")
// 返回默认值或处理错误
}