sclass NLLogicChecker_v2 { S input; new L facts; new LS rules; StringMatcher matcher = ai_standardMatcher(); new L posted; new ThreadLocal checkingRule; VF2 onChecking; // first arg: IfThen or Exp VF3 onChecked; // first arg: IfThen or Exp, last arg: Bool or Throwable sclass Matching { new LinkedHashMap matches; // var -> match new L output; bool verbose; } bool checkRule(final IfThen rule, final Matching m) { if (rule == null) false; ret logCheck(rule, m, func -> Bool { checkRule_impl(rule, m) }); } bool checkRule_impl(IfThen rule, Matching m) { temp tempSetThreadLocal(checkingRule, rule); if (!checkExpression(rule.in, m)) false; m.output.add(apply(rule.out, m)); true; } Exp apply(Exp e, Matching m) { ret apply(e, m.matches); } Exp apply(Exp e, SS m) { if (e == null) null; if (e cast And) ret And(apply(e.a, m), apply(e.b, m)); if (e cast ExpNot) ret ExpNot(apply(e.a, m)); if (e cast Func) ret Func(e.name, apply(e.arg, m)); if (e cast Sentence) ret Sentence(javaTok(matcher.apply(e.text(), m))); if (e cast Sentence2) ret Sentence2(matcher.apply(e.text(), m)); ret e; } A logCheck(O o, Matching m, F0 f) { callF(onChecking, o, m); try { A result = callF(f); callF(onChecked, o, m, result); ret result; } catch e { callF(onChecked, o, m, e); throw rethrow(e); } } final bool checkExpression(final Exp e, final Matching m) { ret logCheck(e, m, func -> Bool { checkExpression_impl(e, m) }); } bool checkExpression_impl(Exp e, Matching m) { if (e cast And) ret checkExpression(e.a, m) && checkExpression(e.b, m); ret checkExpression_single(e, m); } bool checkExpression_single(Exp e, Matching m) { if (e cast ExpNot) { temp tempBackupMatches(m); ret !checkExpression(e.a, m); } if (e cast Func) { if (eq(e.name, "input")) { S pat = nlLogic_text(e.arg); ret nlLogic_matchVBarPattern(this, pat, input, m); } else if (eq(e.name, "fact")) { S pat = nlLogic_text(e.arg); if (contains(e.options, "random")) ret nlLogic_matchRandomFact(this, pat, m); else ret nlLogic_matchAnyFact(this, pat, m); } else if (eq(e.name, "allFacts")) { S pat = nlLogic_text(e.arg); L> l = nlLogic_matchAllFacts(this, pat, m); for i over l: { SS vars = reverseGet(l, i); // facts are normally reversed, so re-reverse to get them in order int n = i+1; for (S var, value : vars) { if (!strictPutIC(m.matches, var + n, value)) false; } } true; } } false; } AutoCloseable tempBackupMatches(final Matching m) { final LinkedHashMap oldMatches = (LinkedHashMap) cloneMap(m.matches); ret autocloseable { m.matches = oldMatches; }; } }