import { Dice } from "../dice"; import { TTCQueryParser } from "./TTCQueryParser"; export class TTCQueryResolver { private parser: TTCQueryParser | null; private context: QueryableObject | null = null; private stack: any[] = []; constructor(parser?: TTCQueryParser) { this.parser = parser || null; } public setParser(parser: TTCQueryParser) { this.parser = parser; } public setContext(obj: QueryableObject) { this.context = obj; } public resolve(resolver: string, onDemand?: boolean) { const resList = resolver.split(","); for (const res of resList) { this.stack.push(this.parseResolver(res)); } const last = this.stack.at(-1); if (typeof last === "function" && !onDemand) return last(); if (onDemand) debugger; return last; } private parseResolver(resolver: string) { if (this.isArithmetic(resolver)) return this.solveArithmetic(resolver); if (this.isQuery(resolver)) return this.runQuery(resolver); } private isQuery(resolver: string) { return ( resolver.startsWith("?") || resolver.startsWith("_") || /^\$\d\./.test(resolver) ); } private runQuery(query: string) { if (!this.parser) throw "Parser not defined in query resolver"; if (query.startsWith("$")) { const [_, idx, q] = query.match(/^(\$\d+)\.(.*)/) || []; if (!_) throw "Detected stack query but did not match the regex"; const stackItem = this.getFromStack(idx); if (typeof stackItem === "string" && Dice.isDice(stackItem)) { return this.handleDice(stackItem, q); } return this.parser.search(q); } // if (query.startsWith("?") || query.startsWith("_")) return query.startsWith("_") && this.context ? this.parser.search(query.replace("_", "^"), this.context).at(0) : this.parser.search(query.replace(/^[?_].?/, "")).at(0); } private handleDice(dice: string, query: string) { const d = new Dice(dice); const [method, n] = query.split(":"); let num = Number(n); if (n && n.startsWith("$")) num = this.getFromStack(n); switch (method) { case "roll": return () => d.roll(); case "rollAvg": return () => d.rollAvg(); case "rollTimes": return () => d.rollTimes(num); case "rollTimesAvg": return () => d.rollTimesAvg(num); default: return "No valid method provided for dice"; } } private isArithmetic(resolver: string) { return resolver.split(/\+|\/|-|\*|\^/).filter((e) => !!e).length > 1; } private solveArithmetic(resolver: string) { const [n1, op, n2] = resolver .match(/(\$?\d+)([+\-*\/^])(\$?\d+)/) ?.slice(1) || ["", "+", ""]; let num1 = Number(n1), num2 = Number(n2); if (n1.startsWith("$")) num1 = this.getFromStack(n1); if (n2.startsWith("$")) num2 = this.getFromStack(n2); switch (op) { case "+": return num1 + num2; case "-": return num1 - num2; case "*": return num1 * num2; case "/": return num1 / num2; case "^": return num1 ^ num2; default: throw "Arithmetic detected but no proper operator assigned"; } } public getFromStack(stackIndex: string): T { const i = Number(stackIndex.replace("$", "")); const val = this.stack[i] as T; return val; } }