sclass NLLogicChecker_v3 extends NLLogicChecker_v2 { List recentHistory; L entities; F2 evaluator; O evalExp(Exp e, Matching m) { ret callF(assertNotNull("No evaluator", evaluator), e, m); } bool checkExpression_impl(Exp e, Matching m) { new Matches mm; if (e cast Func) { // FUNCTION CONDITIONS if (eqOneOf(e.name, "verbPhraseFromThirdPerson", "verbFromThirdPerson")) ret nlLogic_stringFunction(f ai_verbPhraseFromThirdPerson, e, m.matches); else if (eq(e.name, "singular")) ret nlLogic_stringFunction(f singular, e, m.matches); else if (eq(e.name, 'eval)) ret eq("true", str(evalExp(e.arg, m))); else if (eq(e.name, 'entity)) { if (entities == null) { long time = sysNow(); fS switched = switcheroo(input); print("Switched >> " + switched); entities = evalWithTimeoutOrNull(5000, func -> LS { mapMethod('text, ai_extractEntities_v1(switched)) }); print("Entities (" + elapsedMS(time) + " ms): " + joinWithComma(entities)); if (entities == null) entities = new L; } for (S entity : entities) if (matcher.match(nlLogic_text(e.arg), entity, m.matches)) true; } else if (startsWith(e.name, "line", mm) && isInteger(mm.rest())) { int n = parseInt(mm.rest())-nlLogic_numberOfLinesReferenced(checkingRule->in); S line = n == 0 ? input : getString(get(recentHistory, l(recentHistory)+n), 'text); //print("Recent: " + recentHistory); S pat = nlLogic_text(e.arg); //print("n=" + n + ", Matching " + e + " with " + line); ret matcher.match(pat, line, m.matches); } else if (eq(e.name, 'unknownIf)) { S statement = nlLogic_text(apply(e.arg, m)); print("Checking statement: " + statement); ret !cic(facts, statement) && !cic(facts, "Untrue: " + statement); } else if (eq(e.name, 'inputContainsTokens)) ret jcontains(input, nlLogic_text(e.arg)); else if (eq(e.name, 'inputStartsWith)) ret startsWith(input, nlLogic_text(e.arg)); else if (eq(e.name, 'anyInput)) ret nempty(input); else if (eq(e.name, 'preciseInput)) ret eq(nlLogic_text(apply(e.arg, m)), input); // Incomplete var support else if (eq(e.name, 'followingUpOn)) { S text = nlLogic_text(e.arg); Map prevPrev = nextToLast(recentHistory); S msgID = getString(prevPrev, 'globalID); S input = getString(prevPrev, 'text); S ruleID = null, dollarInput = null; // e.g. "lhnshnhcklhabvmu with input=$input" if (match("* with input=*", text, mm) && !isDollarVar(mm.get(1))) { ruleID = mm.unq(0); dollarInput = mm.get(1); } else ruleID = text; //print("followingUpOn: msgID=" + msgID + ", input=" + input); //printStruct(+prevPrev); S pat = format("Rule * fired on message * ", ruleID, msgID); //print("pat=" + pat); for (S ruleFired : mL("Telegram Rule Fires")) if (swic(ruleFired, pat)) { if (dollarInput != null && !strictPutIC(m.matches, dollarInput, input)) false; L tok = javaTokWithBrackets2(ruleFired); if (find3("with vars *", tok, mm)) { SS vars = safeUnstructMap(mm.get(0)); if (!addMapToMapWithoutOverwritingIC(m.matches, vars)) false; } true; } false; } } if (e cast Eq) { // EQUATION CONDITIONS Exp r = e.right; S var = nlLogic_text(e.left); if (endsWith(var, "!")) { // $x != bla temp tempBackupMatches(m); ret !matcher.match(dropSuffixTrim("!", var), r.text(), m.matches); } if (r cast Func) pcall { if (eq(r.name, 'eval)) { O result = evalExp(r.arg, m); if (result != null) { // Not allowing null results anymore LS vars = tok_splitAtComma(var); if (l(vars) == 2 && shortClassNameIs(result, 'Pair)) ret ai_matchMulti(vars, ll(strGet(result, 'a), strGet(result, 'b)), m.matches); if (l(vars) == 3 && shortClassNameIs(result, 'T3)) ret ai_matchMulti(vars, ll(strGet(result, 'a), strGet(result, 'b), strGet(result, 'c)), m.matches); if (result cast Collection) if (l(result) == l(vars)) ret ai_matchMulti(vars, allToString(result), m.matches); S sResult = str(result); StringMatcher _matcher = matcher; if (isDollarVar(var)) _matcher = new NLStringMatcher_singleDollarVar; else if (contains(var, ',')) { // TODO: use Pair instead - there is only like one rule using this if (allDollarVars(vars) && ai_matchMulti(vars, tok_splitAtComma(sResult), m.matches)) true; } ret _matcher.match(var, sResult, m.matches); } } } } ret super.checkExpression_impl(e, m); } void iterate(final Exp e, final Matching m, final Runnable onMatch) { if (e cast And) { iterate(e.a, m, r { iterate(e.b, m, onMatch) }); } if (e cast Func) { if (eq(e.name, "fact")) { S pat = nlLogic_text(e.arg); for (S fact : facts) { temp tempBackupMatches(m); //print("matching " + pat + " with " + fact); if (matcher.match(pat, fact, m.matches)) callF(onMatch); } } } } }