sclass RuleEngine2 { sclass Rule { LS in; S out; Set vars; } int minScore = 50; // minimal percentage score for rule matching int maxLevel = 100, maxOutLines = 10000; new L rules; bool printMappings, printGroupedData, printRejectedVars; O preprocess = f id; // f ai_groupSimplestNounPhrases Set facts = ciSet(); *() {} *(S _rules) { addRules(_rules); } void addRules(S _rules) { _rules = mapEachLine(preprocess, _rules); if (printGroupedData) print(_rules); LPair rules2 = ai_findDoubleArrowRulesAsPairs(_rules); for (PairS rule : rules2) { rule = ai_rule_pair_expandPlusArrow(rule); LS conditions = tok_splitAtPlusAtBeginningOfLine(rule.a); new Rule r; r.in = conditions; r.out = rule.b; r.vars = ai_wordsInBothSidesOfPair_uncurly(rule); rules.add(r); } } LS addFacts(Collection facts) { ret addAllAndReturnNew(this.facts, facts); } void addFact(S fact) { facts.add(fact); } void addAndInterpretFacts(Collection facts) { addFacts(recursiveInterpretations(addFacts(facts))); } void processInput(S input) { print("\nInput: " + tok_dropCurlyBrackets(input)); temp tempIndent(); for (S in : interpretations(input)) { print("\nInterpretation: " + formatForUser(in)); Set out = litciset(); interpretRecursively(in, 5, out); } } Set recursiveInterpretations(S in) { ret recursiveInterpretations(ll(in)); } Set recursiveInterpretations(Iterable in) { Set inSet = asCISet(in); Set out = litciset(); new LinkedHashSet queue; addAll(queue, inSet); while (l(out) < maxOutLines && nempty(queue)) { LS intp = interpretations(popFirst(queue)); for (S i : intp) if (!inSet.contains(i) && !out.contains(i)) { out.add(i); queue.add(i); if (l(out) >= maxOutLines) break; } } ret out; } void interpretRecursively(S input, int level, Set out) { if (level <= 0) ret; LS interpretations = interpretations((S) callF(preprocess, input)); temp tempIndent(); for (S in : addAllAndReturnNew(out, interpretations)) { print(" => " + formatForUser(in)); for (S s : lithashset(in, ai_superSimpleVerbCorrector(in))) interpretRecursively(s, level-1, out); } } LS defaultParse(S s) { ret codeTokens_lazy_uncurly(javaTokNPunctuationWithBrackets_cached(s)); } LS interpretations(S input) { LS tokI = defaultParse(input); //print("Raw parse: " + tokI); new LS interpretations; for (Rule rule : rules) { continue unless l(rule.in) == 1; LS tokR = defaultParse(first(rule.in)); final SS map = ciMapWithoutKeysEqualToValues(zipTwoListsToCIMap_strict(tokR, tokI)); if (map == null) continue; // Found matching rule int score = l(tokR)-l(map); L nonVars = withoutDollarVars(listMinusSet(keys(map), rule.vars)); if (printRejectedVars && nempty(nonVars)) print("Rejected vars: " + nonVars); if (nempty(nonVars)) score = 0; int percentScore = ratioToIntPercent(score, l(tokR)); if (printMappings) print(" " + percentScore + "% " + reverseMapCI_joinDuplicatesWithPlus(map) + " | " + rule.in); if (percentScore < minScore) continue; // Make consequence S c = rule.out; c = join(mapCodeTokens(javaTok(c), func(S s) -> S { getOrKeep_tryUncurlied(map, s) })); c = join(mapCodeTokens(javaTokWithBrackets(c), func(S s) -> S { getOrKeep_tryUncurlied(map, s) })); //c = javaTokWithBrackets_recursiveTransform(func(S s) -> S { getOrKeep(map, s) }, c); interpretations.add(c); } ret interpretations; } S formatForUser(S s) { ret ai_superSimpleVerbCorrector(tok_dropCurlyBrackets(s)); } LPair rulesAsPairs() { ret map(rules, func(Rule r) -> Pair { pair(r.in, r.out) }); } }