sclass RuleEngine { new LL facts; // stores code token parses Map phrasesWordTree = wordTree(); Clusters clusters = ciClusters(); new Prolog prolog; *(S program) { this("", program); } *(S program, bool showStuff) { if (showStuff) showStuff(); runProgram(program); } *(S inspiration, S program) { runProgram(inspiration, program); } void runProgram(S program) { runProgram("", program); } void runProgram(S inspiration, S program) { for (S s : tlftj(inspiration)) addFact("inspired " + quote(s)); L programLines = tlftj(program); //pnl(program); //print(); for (S s : programLines) { Pair> p = parseFunctionCall(s); if (p != null) { //print("Function call: " + sfu(p)); S f = p.a; L args = p.b; if (eqic(f, "assert")) assertFact(getSingleton(p.b)); else if (swic(f, "assert_")) { if (eqic(f, "assert_answer")) assertAnswer(unquote(first(args)), unquote(second(args))); else if (eqic(f, "assert_parse")) assertParse(args); else fail("Unknown assertion function: " + f); } else if (eqic(f, "fact_question_answer_upperCaseVars")) prolog.code( dontPrint("if [" + toProlog(unquote(first(args))) + "] and [" + toProlog(unquote(second(args))) + "] then [answer is [" + toProlog(unquote(third(args))) + "]]")); continue; } L tok = javaTok(s); if (eqic(second(tok), "assert")) { assertFact(join(dropFirst(3, tok))); continue; } int i = indexOfSubListLL(tok, "-", "", ">"); if (i >= 0) { L left = subList(tok, 1, i-1); int j = indexOf(left, "+"); if (j >= 0) { prolog.code( print("if [" + toProlog(joinSubList(left, 0, j-1)) + "] and [" + toProlog(joinSubList(left, j+2)) + "] then [" + toProlog(joinSubList(tok, i+4)) + "]")); continue; } } tok = codeTokens(tok); if (eqic(getSingletonOpt(tok), "rewrite")) continue with addFactsFromProlog(prolog.rewriteAndSave()); if (l(tok) == 2 && isIdentifier(first(tok)) && isQuoted(second(tok))) if (eq(first(tok), "phrase")) { addPhrase(unquote(second(tok))); continue; } if (l(tok) == 3 && eq(second(tok), "=")) { ciClusters_add(clusters, addPhrase(unquote(first(tok))), addPhrase(unquote(third(tok)))); continue; } addFact(s); } } void printStuff { printAsciiHeading("Facts"); pnlStruct(facts); print(); print("Clusters: " + sfu(clusters)); print("Phrases: " + sfu(phrasesWordTree)); } L parseFact(S s) { L tok = map toLowerIfIdentifier(javaTokWithAngleBracketsC(/*dropPunctuation*/(s))); ret nempties(translateUsingWordTreeC(tok, phrasesWordTree)); } void assertFact(S fact) { if (contains(facts, parseFact(fact))) print("OK fact: " + fact); else print("FAILED fact assert: " + fact); } void assertAnswer(S q, S a) { Prolog p = new(prolog); //p.showStuff = true; p.code(dontPrint("to prolog: ", squareBracket(toProlog(q)))); L out = p.rewrite(); //print("Got " + l(out) + " statement(s)"); L lines = map nlUnparse(out); L answers = startingWithEndingWith_drop(lines, "answer is [", "]"); if (l(answers) == 1 && eqic(first(answers), a)) print("OK answer: " + q + " -> " + a); else { pnl(map nlUnparse(out)); print("FAIL answer: " + q + " -> " + first(answers) + " - expected: " + a); } } S addPhrase(S s) { wordTreeAdd(phrasesWordTree, javaTokC(s), s); ret s; } void addFact(S s) { L tok = parseFact(s); facts.add(tok); prolog.code(dontPrint("to prolog: ", squareBracket(factToProlog(tok)))); } void assertParse(L args) { args = unquoteAll(args); S s = first(args); L parsed = parseFact(s); L expected = dropFirst(args); if (eq(parsed, expected)) print("OK parse: " + s + " -> " + sfu(parsed)); else print("FAILED parse: " + s + " -> " + sfu(parsed) + " - expected: " + sfu(expected)); } S toProlog(S s) { L tok = parseFact(upperCaseVarsToDollarVars(s)); ret factToProlog(tok); } S factToProlog(L tok) { ret joinWithSpace(map ruleEngine_tokenToProlog(tok)); } void addFactsFromProlog(L l) { addFacts(printAll(map nlUnparse(l))); } void addFacts(L l) { for (S s : unnull(l)) addFact(s); } RuleEngine showStuff() { prolog.showStuff = true; this; } }