sclass NLLogicChecker_v2 { S input; new L facts; StringMatcher matcher = ai_standardMatcher(); new L posted; new ThreadLocal checkingRule; VF3 onExpressionChecked; sclass Matching { new LinkedHashMap matches; // var -> match new L output; bool verbose; } bool checkRule(IfThen rule, Matching m) { if (rule == null) false; temp tempSetThreadLocal(checkingRule, rule); if (!checkExpression(rule.in, m)) false; print("Rewriting output: " + sfu(rule.out)); 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; } final bool checkExpression(Exp e, Matching m) { try { bool result = checkExpression_impl(e, m); recordExpressionCheck(e, m, result); ret result; } catch e { recordExpressionCheck(e, m, e); throw rethrow(e); } } void recordExpressionCheck(Exp e, Matching m, O result) { callF(onExpressionChecked, e, m, result); } bool checkExpression_impl(Exp e, Matching m) { if (e cast And) ret checkExpression(e.a, m) && checkExpression(e.b, 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); L tok = javaTokPlusBrackets2(pat); for (S pat2 : splitAtTokens(tok, ll("|"))) { bool result = matcher.match(pat2, input, m.matches); if (m.verbose) print("matched " + sfu(e) + " with " + quote(input) + " & " + sfu(m.matches) + " => " + result); if (result) true; } } else if (eq(e.name, "fact")) { S pat = nlLogic_text(e.arg); for (S fact : facts) { bool result = matcher.match(pat, fact, m.matches); if (m.verbose) print("matched " + sfu(e) + " with " + quote(fact) + " & " + sfu(m.matches) + " => " + result); if (result) true; } } } false; } AutoCloseable tempBackupMatches(final Matching m) { final LinkedHashMap oldMatches = (LinkedHashMap) cloneMap(m.matches); ret autocloseable { m.matches = oldMatches; }; } }