fix(journal): unify $var lookup and error

EvalContext.lookup now receives the full $var name, matching getCombined,
setBase, and getMods, and parseFactor throws "Unknown variable" when the
lookup returns undefined. /set and /roll use the new resolveVariable() so a
typo errors instead of silently evaluating to 0.

Declarations and tag modifiers stay lenient (unknown -> 0): the documented
$hp = $con*5+$mod_hp pattern depends on external/undeclared variables
defaulting to 0.
This commit is contained in:
hyper
2026-09-12 22:34:12 +08:00
parent 02442a1100
commit 16f2038fd8
6 changed files with 83 additions and 41 deletions
+5 -7
View File
@@ -11,7 +11,7 @@ import { parseInput } from "./command-parser";
import { resolveRollPayload } from "./types/roll";
import { resolveSparkPayload } from "./types/spark";
import { evaluateExpression, exprValueToString } from "./variable-expression";
import { computeCascade, getCombined, setBase } from "./var-reactivity";
import { computeCascade, getCombined, resolveVariable, setBase } from "./var-reactivity";
import { ensureReactivity } from "./completions";
// Tagmap pattern: "#warrior:1;#druid:2". Also accepts bare "#tag" as shorthand.
@@ -131,7 +131,8 @@ export async function dispatchCommand(
if (arg.includes("$")) {
try {
const ev = evaluateExpression(arg, {
lookup: (name: string) => getCombined("$" + name, ctx.variables),
// Strict: referencing an undefined variable is an error, not 0.
lookup: (name) => resolveVariable(name, ctx.variables),
});
if (ev.value.kind !== "number") {
return finish({ ok: false, error: "Roll expression must evaluate to a number" });
@@ -204,11 +205,8 @@ function dispatchSet(
} else if (p.expr) {
// Evaluate expression — handles both numeric and tagmap values
const result = evaluateExpression(p.expr, {
lookup: (name: string) => {
const k = "$" + name;
// Use getCombined with stream fallback for accurate values
return k === key ? undefined : getCombined(k, ctx.variables);
},
// Strict: referencing an undefined variable is an error, not 0.
lookup: (name) => resolveVariable(name, ctx.variables),
});
newValue = exprValueToString(result.value);
} else {