sclass NewWoody { transient Map rulesByName; transient new L badRules; Map ruleData = ciMap(); S lastOutput; BBRule lastRule, activeRule, gotoRule; S prefix = "BB | "; sclass RuleData { int answerIndex; } RuleData ruleData(BBRule rule) { ret getOrCreate(ruleData, rule.listName, RuleData.class); } *() { if (!DynamicObject_isLoading()) rulesByName = indexFieldAsCIMap('listName, bb_allRules()); } *(NewWoody w) { initFrom(w); } void initFrom(NewWoody w) { copyFields(w, this, 'rulesByName, 'badRules); } void processInput(S input) { lastRule = null; lastOutput = null; temp tempSetTL(ctxContext_var(), nu(CtxContext, +input)); new L matching; if (nempty(input)) for (BBRule r : valuesList(rulesByName)) if (ruleExpressionMatches(r)) matching.add(r); setActiveRule(or(first(matching), activeRule)); repeat 10 { gotoRule = null; doRule(); if (gotoRule == null) break; setActiveRule(gotoRule); } } void doRule { if (activeRule != null) if (cic(activeRule.answerMode, 'random)) // TODO: mark seen setOutput(random(activeRule.answers)); else if (cic(activeRule.answerMode, 'switch)) { for (S s : activeRule.answers) { LS l = splitAtDoubleArrow(s); if (l(l) == 2 && print(first(l), ctxEvalCondition(first(l)))) { setOutput(second(l)); break; } } } else { // loop RuleData rd = ruleData(activeRule); setOutput(get(activeRule.answers, rd.answerIndex %= max(1, l(activeRule.answers)))); ++rd.answerIndex; } } bool ruleExpressionMatches(BBRule r) { if (empty(r.expression)) false; try { ret ctxEvalCondition(r.expression); } catch print e { badRules.add(r); rulesByName.remove(r.listName); false; } } L listsMatchingInput(S input) { temp tempSetTL(ctxContext_var(), nu(CtxContext, +input)); ret [BBRule r : valuesList(rulesByName) | ruleExpressionMatches(r)]; } void setOutput(S s) { new Matches m; if (swic_trim(trim(lastLine(s)), "goto:", m)) { S ruleName = prefix + m.rest(); gotoRule = rulesByName.get(ruleName); print("Goto: " + ruleName + " (" + yesNo(gotoRule != null) + ")"); s = dropLastLine(s); } lastOutput = appendSpaceIfNempty(lastOutput) + s; } void setActiveRule(BBRule rule) { activeRule = lastRule = or(rule, activeRule); } }