Libraryless. Click here for Pure Java version (8848L/59K).
1 | sclass PhilosophyBot1 { |
2 | static transformable record LogicRule(lhs, rhs) { |
3 | int n; // when added |
4 | |
5 | toString { |
6 | ret (n == 0 ? "" : "[" + n + "] ") + lhs + " => " + rhs; |
7 | } |
8 | } |
9 | static transformable record And(a, b) {} |
10 | static transformable record If(condition, thenBlock, elseBlock) {} |
11 | static transformable record For(var, condition, body) {} // don't need var actually |
12 | static transformable record ForIn(var, expr, body) {} |
13 | static transformable record While(condition, body) {} |
14 | |
15 | replace NPRet with O. // native predicate return type (Bool/SS/null) |
16 | |
17 | // like a native predicate, but doesn't return anything |
18 | sclass CodeFragment { |
19 | S head; |
20 | IVF2<SS, Env> body; |
21 | bool keepBrackets; |
22 | |
23 | *(S *head, IVF2<SS, Env> *body, bool *keepBrackets) {} |
24 | *(S *head, IVF2<SS, Env> *body) {} |
25 | |
26 | toString { ret stdToString(this); } |
27 | } |
28 | |
29 | sclass Env { |
30 | bool wantAlternatives; |
31 | |
32 | bool wantAlternatives() { ret wantAlternatives; } |
33 | } |
34 | |
35 | srecord WithAlternative(IF0<O> alternative, O result) {} |
36 | |
37 | // body takes variable mapping |
38 | // body can return |
39 | // Bool => immediate result (ok or fail) |
40 | // SS => variable mapping |
41 | // WithAlternative |
42 | // Iterator<NPRet> |
43 | // null => not applicable |
44 | // For "for $x in ..." statements, return a Iterable<stringable>? |
45 | srecord NativePredicate(S head, IF2<SS, Env, NPRet> body) {} |
46 | |
47 | replace ProcedureToRun with Proc. |
48 | replace Proc with L. // procedures are a list of statements |
49 | |
50 | // trail of a transformed fact |
51 | srecord TTransformed(S fact, IF1<S> transformer) {} |
52 | |
53 | transient S program; |
54 | transient bool programLoaded; |
55 | transient int maxRounds = 1000; |
56 | transient int maxFacts = 1000; |
57 | transient Set<S> facts = linkedCISet(); |
58 | transient Set<S> originalFacts = ciSet(); |
59 | transient new LinkedHashSet<LogicRule> logicRules; // modified with sync |
60 | transient new AllOnAll<LogicRule, S> rulesOnFacts; |
61 | transient new AllOnAll<CodeFragment, S> codeOnFacts; |
62 | transient new AllOnAll<IVF1<S>, S> anyCodeOnFacts; |
63 | transient new L<ProcedureToRun> proceduresToRun; |
64 | // parsed procedures |
65 | transient long proceduresExecuted; |
66 | transient new L<NativePredicate> nativePredicates; |
67 | transient bool debugNativeCalls = true, debugAllCmds = true; |
68 | transient bool verbose = true; |
69 | transient new L onProcedureEnded; |
70 | transient new L<IVF1<LogicRule>> onLogicRuleAdded; |
71 | transient new L<IVF1<S>> onFactAdded; |
72 | transient bool printNonMatches, debugContradictionChecks; |
73 | transient bool standardImportsLoaded; |
74 | transient bool curryAllRules = true; // rewrite "a & b => c" to a => b => c |
75 | transient int logicRulesCounter; |
76 | transient bool thoughtBegun; |
77 | transient bool printFactsAfterThinking = true; |
78 | |
79 | // return true when you handled adding the rule |
80 | transient new L<IPred<LogicRule>> logicRulePreprocessors; |
81 | |
82 | // return true when you handled adding the fact |
83 | transient new L<IPred<S>> factPreprocessors; |
84 | |
85 | // extra stuff that is done every round |
86 | transient new L<Runnable> extraLogicOperations; |
87 | |
88 | transient Set<S> vars = litciset("x", "y", "z"); |
89 | |
90 | // phrase replacements that are made in every fact. |
91 | // functionality is enabled by philosophyBot1_addDeepReplacement |
92 | transient SS deepReplacements; |
93 | |
94 | transient L<IF1<S>> deepTransformers; |
95 | |
96 | // fact -> trail. to enable, initialize with ciMap() |
97 | transient MapSO trails; |
98 | |
99 | Map extensions; |
100 | |
101 | *() { |
102 | // find contradictions |
103 | anyCodeOnFacts.newA(fact -> { |
104 | Bool b = checkNativeCondition(fact); |
105 | if (debugContradictionChecks) |
106 | print("Fact check: " + b + " - " + fact); |
107 | if (isFalse(b)) |
108 | addFactWithTrail("contradiction", trails == null ? null : fact); |
109 | }); |
110 | |
111 | _standardHandlers(); |
112 | } |
113 | *(S *program) { this(); } |
114 | |
115 | void addRule(S s) { |
116 | PairS p = splitAtFirstDoubleArrow(javaTokWithBrackets(s)); |
117 | if (p == null) if (verbose) print("addRule failed: " + s); |
118 | addLogicRule(new LogicRule(splitAtAmpersand2(p.a), p.b)); |
119 | } |
120 | |
121 | void addRules(Iterable<S> l) { |
122 | fOr (S s : l) addRule(s); |
123 | } |
124 | |
125 | O splitRuleRHS(O rhs) { |
126 | if (rhs cast S) { |
127 | PairS p = splitAtFirstDoubleArrow(javaTokWithBrackets(rhs)); |
128 | if (p != null) ret splitRuleRHS(new LogicRule(splitAtAmpersand2(p.a), splitRuleRHS(p.b))); |
129 | |
130 | ret splitAtAmpersand2(rhs); |
131 | } |
132 | ret rhs; |
133 | } |
134 | |
135 | LogicRule curryLHS(LogicRule rule) { |
136 | while licensed { |
137 | O lhs = rule.lhs; |
138 | if lhs is And(O a, O b) |
139 | rule = new LogicRule(a, new LogicRule(b, rule.rhs)); |
140 | else break; |
141 | } |
142 | ret rule; |
143 | } |
144 | |
145 | void addLogicRule(LogicRule rule) { |
146 | rule.rhs = splitRuleRHS(rule.rhs); |
147 | |
148 | if (curryAllRules) |
149 | rule = curryLHS(rule); |
150 | |
151 | for (IPred<LogicRule> p : logicRulePreprocessors) |
152 | if (p.get(rule)) ret; // has been preprocessed |
153 | |
154 | rule.n = ++logicRulesCounter; |
155 | |
156 | // is LHS a native predicate? then eval immediately |
157 | // TODO: multiple conditions |
158 | Bool b = checkConditionOpt(rule.lhs); |
159 | if (isFalse(b)) ret; // drop rule |
160 | if (isTrue(b)) |
161 | addRewrittenRHS(rule.rhs, rule); |
162 | |
163 | if (syncAdd(logicRules, rule)) { |
164 | if (verbose) print("Got logic rule", rule); |
165 | pcallFAll(onLogicRuleAdded, rule); |
166 | rulesOnFacts.newA(rule); // to combine it with the facts |
167 | } |
168 | } |
169 | |
170 | void addFacts(Iterable<S> l) { |
171 | fOr (S fact : l) addFact(fact); |
172 | } |
173 | |
174 | void addFactWithTrail(S fact, O trail) { |
175 | addFact(fact); |
176 | mapPut(trails, fact, trail); |
177 | } |
178 | |
179 | void addFact(S fact) { |
180 | ping(); |
181 | fact = trim(fact); |
182 | if (empty(fact)) ret; |
183 | |
184 | if (l(facts) >= maxFacts) ret; |
185 | |
186 | fact = tok_deRoundBracket(fact); |
187 | |
188 | for (IPred<S> p : factPreprocessors) |
189 | if (p.get(fact)) ret; // has been preprocessed |
190 | |
191 | // Check if it's a procedure |
192 | LS tok = mainTokenize(fact); |
193 | if (countCodeTokens(tok) == 2 && firstTokenEqic(tok, "proc") |
194 | && isCurlyBracketed(getCodeToken(tok, 1))) pcall { |
195 | // It's a procedure! |
196 | S proc = uncurly_keepSpaces(getCodeToken(tok, 1)); |
197 | if (proceduresToRun.add(parseProcedure(proc))) { |
198 | if (verbose) print("Got procedure:"); |
199 | if (verbose) print(indentx("> ", proc)); |
200 | } |
201 | } /*else if (countCodeTokens(tok) == 2 && firstTokenEqic(tok, "java") |
202 | && isCurlyBracketed(getCodeToken(tok, 1))) pcall { |
203 | // It's Java code |
204 | |
205 | }*/ else // It's a fact, not a procedure |
206 | if (facts.add(fact)) { |
207 | if (verbose) print("Got fact: " + fact); |
208 | pcallFAll(onFactAdded, fact); |
209 | rulesOnFacts.newB(fact); // to combine it with the rules |
210 | codeOnFacts.newB(fact); |
211 | anyCodeOnFacts.newB(fact); |
212 | } |
213 | } |
214 | |
215 | void addRewrittenRHS(O o, O trail) { |
216 | if (o cast LogicRule) |
217 | addLogicRule(o); |
218 | else if o is And(O a, O b) { |
219 | addRewrittenRHS(a, o); |
220 | addRewrittenRHS(b, o); |
221 | } else if (o != null) |
222 | addFactWithTrail((S) o, trail); |
223 | } |
224 | |
225 | void addFactFromProgram(S fact) { |
226 | if (countJavaTokens(fact) == 0) ret; |
227 | fact = javaDropAllComments(fact); |
228 | originalFacts.add(fact); |
229 | addFact(fact); |
230 | } |
231 | |
232 | void runProcedure(S proc) pcall { |
233 | if (verbose) print("Running procedure."); |
234 | runParsedProcedure(parseProcedure(proc)); |
235 | } |
236 | |
237 | void runParsedProcedure(Proc commands) { |
238 | runParsedProcedure(commands, proceduresToRun); |
239 | } |
240 | |
241 | void runParsedProcedure(Proc commands, L<Proc> whereToPostCode) { |
242 | ++proceduresExecuted; |
243 | new Env env; |
244 | L remainingCommands = cloneLinkedList(commands); |
245 | O cmd; |
246 | while not null (cmd = popFirst_ping(remainingCommands)) { |
247 | if (cmd cast L) continue with runParsedProcedure(cmd); |
248 | if (cmd cast Runnable) continue with cmd.run(); |
249 | if (debugAllCmds) |
250 | print("Running cmd: " + sfu(cmd)); |
251 | if cmd is If(O condition, O thenBlock, O elseBlock) { |
252 | O blockToRun = checkCondition(condition) ? thenBlock : elseBlock; |
253 | runParsedProcedure(ll(blockToRun)); |
254 | } else if cmd is For(O var, O condition, O body) { |
255 | // make a new logic rule and add it |
256 | // assume the variable is globally declared as a variable |
257 | addLogicRule(new LogicRule(condition, "proc {\n" + body + "\n}")); |
258 | } else if cmd is While(O condition, O body) { |
259 | bool b = checkCondition(condition); |
260 | if (!b) continue; |
261 | whereToPostCode.add(ll(body, cmd)); |
262 | } else if cmd is ForIn(S var, S expr, O body) { |
263 | // XXX |
264 | O result = runNativePredicate(expr, new Env); |
265 | if (!result instanceof Iterable) { |
266 | if (verbose) print("Warning: result of " + expr + " not iterable (" + shortClassName(result) + ")"); |
267 | continue; |
268 | } |
269 | Iterator it = iterator((Iterable) result); |
270 | Runnable step = r { |
271 | if (!it.hasNext()) ret; |
272 | S value = str(it.next()); |
273 | SS map = litcimap(var, value); |
274 | O body2 = replaceVars(body, map); |
275 | //print("ForIn: " + map + " => " + body2); |
276 | whereToPostCode.add(ll(body2, this)); |
277 | }; |
278 | step.run(); |
279 | } else if (cmd cast S) { |
280 | O result = runNativePredicate(cmd, env); |
281 | if (result != null) { |
282 | result = unpackWithAlternativeOrIterator(result); |
283 | if (isFalse(result)) ret; |
284 | if (isTrueOpt(result)) continue; |
285 | SS mapping = cast result; // assume it's a variable mapping |
286 | // apply to all remaining commands and continue |
287 | L remainingCommands2 = mapToLinkedList(remainingCommands, |
288 | c -> replaceVars(c, mapValues optRound(mapping))); |
289 | if (verbose) print("Applying var mapping " + mapping + " to " + remainingCommands |
290 | + " => " + remainingCommands2); |
291 | remainingCommands = remainingCommands2; |
292 | } else |
293 | addFact(cmd); |
294 | } else if (cmd != null) |
295 | fail("Unimplemented command: " + cmd); |
296 | } |
297 | pcallFAll(onProcedureEnded, commands); // notify listeners |
298 | } |
299 | |
300 | // return var mapping (SS), Bool or null for no matching predicate |
301 | // or result verbatim (e.g. Iterable) |
302 | O runNativePredicate(S s, Env env) { |
303 | for (NativePredicate np : nativePredicates) { |
304 | SS map = zipIt(np.head, s); |
305 | if (map != null) { |
306 | O result = np.body.get(mapValues tok_deRoundBracket(map), env); |
307 | if (debugNativeCalls) |
308 | print("Native predicate result: " + np.head + " => " + result); |
309 | if (result instanceof Map && nempty(map)) { |
310 | result = mapKeys((SS) result, var -> lookupOrKeep(map, var)); |
311 | if (debugNativeCalls) |
312 | print("Rewrote native predicate result: " + result); |
313 | } |
314 | try object result; |
315 | } else |
316 | if (printNonMatches) |
317 | print("Non-match: " + quote(np.head) + " / " + quote(s)); |
318 | } |
319 | null; |
320 | } |
321 | |
322 | // returns false if unknown |
323 | bool checkCondition(O o) { |
324 | ret isTrue(checkConditionOpt(o)); |
325 | } |
326 | |
327 | // returns null if unknown |
328 | Bool checkConditionOpt(O o) { |
329 | if (o cast S) { |
330 | if (contains(facts, o)) true; |
331 | try object Bool b = checkNativeCondition(o); |
332 | } |
333 | //print("Ignoring condition: " + o); |
334 | null; |
335 | } |
336 | |
337 | Bool checkNativeCondition(S o) { |
338 | O result = runNativePredicate(o, new Env); |
339 | result = unpackWithAlternativeOrIterator(result); |
340 | if (result cast Bool) ret result; |
341 | if (result instanceof Map) true; // TODO |
342 | null; |
343 | } |
344 | |
345 | !include #1025614 // parsePythonesqueProcedure |
346 | |
347 | Proc parseProcedure(S s) { |
348 | ret parsePythonesqueProcedure(s); |
349 | } |
350 | |
351 | O splitAtAmpersand2(S s) { |
352 | LS l = tok_splitAtAmpersand(s); |
353 | if (l(l) == 1) ret s; |
354 | ret new And(first(l), splitAtAmpersand2(join(" & ", dropFirst(l)))); |
355 | } |
356 | |
357 | // "zip" a condition with a fact (match word-by-word) |
358 | SS zipIt(S cond, S fact) { |
359 | SS map = zipIt_keepBrackets(cond, fact); |
360 | if (map == null) null; // no match |
361 | ret mapValues tok_deRoundOrCurlyBracket(map); |
362 | } |
363 | |
364 | SS zipIt_deBracket(S pat, S s) { |
365 | SS map = zipIt(pat, s); |
366 | ret map == null ? null : mapValues tok_deRoundOrCurlyBracket(map); |
367 | } |
368 | |
369 | // "zip" a condition with a fact (match word-by-word) |
370 | SS zipIt_keepBrackets(S cond, S fact) { |
371 | SS map = gazelle_deepZip_keepBrackets(cond, fact); |
372 | if (map == null) null; // no match |
373 | if (!all(keys(map), s -> isVar(s))) null; /*with print("Non-variable changes, exiting")*/; |
374 | ret map; |
375 | } |
376 | |
377 | bool isVar(S s) { |
378 | ret s != null && |
379 | (vars.contains(s) || s.startsWith("var_") || isDollarVar(s)); |
380 | } |
381 | |
382 | O replaceVars(O o, SS map) { |
383 | if (empty(map)) ret o; |
384 | ret transform(x -> replaceVars_base(x, map), o); |
385 | } |
386 | |
387 | O replaceVars_base(O o, SS map) { |
388 | if (o cast S) |
389 | ret replaceCodeTokensUsingMap(o, map); |
390 | null; |
391 | } |
392 | |
393 | S format(S s, SS map) { |
394 | ret replaceCodeTokensUsingMap(s, mapValues optRound(map)); |
395 | } |
396 | |
397 | // if f returns null, go through structure |
398 | O transform(IF1 f, O o) { |
399 | if (o == null) null; |
400 | ping(); |
401 | try object f.get(o); |
402 | |
403 | if (o cast Transformable) |
404 | ret o.transformUsing(x -> transform(f, x)); |
405 | |
406 | if (o cast L) |
407 | ret map(x -> transform(f, x), o); |
408 | |
409 | fail("Don't know how to transform: " + className(o)); |
410 | } |
411 | |
412 | void applyLogicRuleToFact(LogicRule rule, S fact) { |
413 | O lhs = rule.lhs, rhs = rule.rhs; |
414 | O cond, remaining = null; |
415 | if lhs is And(O a, O b) { |
416 | cond = a; |
417 | remaining = b; |
418 | } else |
419 | cond = lhs; |
420 | |
421 | // now we match the condition with the fact |
422 | SS map = zipIt_keepBrackets((S) cond, fact); |
423 | if (map == null) { |
424 | if (printNonMatches) |
425 | print("Non-match: " + quote(cond) + " / " + quote(fact)); |
426 | ret; // no match |
427 | } |
428 | |
429 | // Now we have a proper mapping with the keys being variables! |
430 | if (verbose) print("Match: " + quote(cond) + " / " + quote(fact)); |
431 | |
432 | // drop round brackets |
433 | // XXX? map = mapValues tok_deRoundBracket(map); |
434 | |
435 | // Apply mapping to right hand side |
436 | O rhs_replaced = replaceVars(rhs, map); |
437 | if (verbose) print(+rhs_replaced); |
438 | |
439 | if (remaining == null) { |
440 | // Add as fact / new rule |
441 | addRewrittenRHS(rhs_replaced, rule); |
442 | } else { |
443 | // Apply mapping to remaining condition |
444 | O remaining_replaced = replaceVars(remaining, map); |
445 | addLogicRule(new LogicRule(remaining_replaced, rhs_replaced)); |
446 | } |
447 | } |
448 | |
449 | run { think(); } |
450 | |
451 | !include #1025615 // smartParser1 |
452 | |
453 | void parseProgram { |
454 | if (programLoaded) ret; |
455 | set programLoaded; |
456 | loadProgram(program); |
457 | } |
458 | |
459 | void loadProgram(S program) { |
460 | smartParser1(program); |
461 | } |
462 | |
463 | bool doSomeLogic() { |
464 | bool anyAction; |
465 | Pair<LogicRule, S> p; |
466 | while not null (p = rulesOnFacts.next()) { |
467 | ping(); |
468 | set anyAction; |
469 | //print("Combination: " + p); |
470 | applyLogicRuleToFact(p.a, p.b); |
471 | } |
472 | Pair<CodeFragment, S> p2; |
473 | while not null (p2 = codeOnFacts.next()) { |
474 | ping(); |
475 | set anyAction; |
476 | //print("Combination: " + p2); |
477 | applyCodeFragmentToFact(p2.a, p2.b); |
478 | } |
479 | Pair<IVF1<S>, S> p3; |
480 | while not null (p3 = anyCodeOnFacts.next()) { |
481 | ping(); |
482 | set anyAction; |
483 | //print("Combination: " + p3); |
484 | pcallF(p3.a, p3.b); |
485 | } |
486 | ret anyAction; |
487 | } |
488 | |
489 | void applyCodeFragmentToFact(CodeFragment cf, S fact) { |
490 | SS map = cf.keepBrackets ? zipIt_keepBrackets(cf.head, fact) : zipIt(cf.head, fact); |
491 | if (map != null) |
492 | cf.body.get(mapValues tok_deRoundBracket(map), new Env); |
493 | } |
494 | |
495 | // indicator for end of thought process (when this stays stable) |
496 | long size() { |
497 | ret l(logicRules) + l(facts) + proceduresExecuted; |
498 | } |
499 | |
500 | void think { |
501 | parseProgram(); |
502 | |
503 | set thoughtBegun; |
504 | |
505 | int round = 0; |
506 | |
507 | while ping (round++ < maxRounds) { |
508 | long lastSize = size(); |
509 | if (verbose) print("Logic round " + round + ", size: " + lastSize); |
510 | while (doSomeLogic() && round++ < maxRounds && l(facts) < maxFacts) {} |
511 | |
512 | for ping (Proc proc : getAndClearList(proceduresToRun)) |
513 | runParsedProcedure(proc); |
514 | |
515 | callFAll(extraLogicOperations); |
516 | |
517 | if (size() == lastSize) { |
518 | if (verbose) print("No changes, exiting"); |
519 | break; |
520 | } |
521 | } |
522 | |
523 | // We're done logicking, so print all the facts gathered |
524 | |
525 | Cl<S> madeFacts = factsDeduced(); |
526 | if (printFactsAfterThinking) |
527 | pnlWithHeading("Facts I deduced", madeFacts); |
528 | |
529 | // Print say () and print () separately |
530 | |
531 | new LS output; |
532 | for (S fact : madeFacts) { |
533 | LS tok = mainTokenize(fact); |
534 | if (countCodeTokens(tok) == 2 && eqicOneOf(getCodeToken(tok, 0), "print", "say")) |
535 | // For the user, we print without all the round brackets |
536 | output.add(tok_dropRoundBrackets(getCodeToken(tok, 1))); |
537 | } |
538 | |
539 | pnlWithHeadingIfNempty("Bot Output", output); |
540 | } |
541 | |
542 | void addNativePredicate(S head, IF0 body) { |
543 | nativePredicates.add(new NativePredicate(head, (map, env) -> body!)); |
544 | } |
545 | |
546 | void addNativePredicate(S head, IF1<SS, O> body) { |
547 | nativePredicates.add(new NativePredicate(head, (map, env) -> body.get(map))); |
548 | } |
549 | |
550 | void addNativePredicate(S head, IF2<SS, Env, NPRet> body) { |
551 | nativePredicates.add(new NativePredicate(head, body)); |
552 | } |
553 | |
554 | // when you only need one result |
555 | O unpackWithAlternativeOrIterator(O result) { |
556 | if (result instanceof Iterator) ret first((Iterator) result); |
557 | if (result instanceof WithAlternative) ret ((WithAlternative) result).result; |
558 | ret result; |
559 | } |
560 | |
561 | void onFactDo(S head, IVF2<SS, Env> body) { |
562 | codeOnFacts.newA(new CodeFragment(head, body)); |
563 | } |
564 | |
565 | void onFactDo_keepBrackets(S head, IVF2<SS, Env> body) { |
566 | codeOnFacts.newA(new CodeFragment(head, body, true)); |
567 | } |
568 | |
569 | LS filterByPattern(S pat, Iterable<S> items) { |
570 | ret filter(items, i -> zipIt(pat, i) != null); |
571 | } |
572 | |
573 | // pat = pattern with variables |
574 | // results are mappings with debracketed values |
575 | L<SS> matchFacts(S pat) { |
576 | ret matchStrings(pat, facts); |
577 | } |
578 | |
579 | SS matchString(S pat, S input) { |
580 | ret zipIt_deBracket(pat, input); |
581 | } |
582 | |
583 | L<SS> matchStrings(S pat, Iterable<S> items) { |
584 | new L<SS> out; |
585 | for (S s : items) { |
586 | SS map = zipIt_deBracket(pat, s); |
587 | if (map != null) |
588 | out.add(map); |
589 | } |
590 | ret out; |
591 | } |
592 | |
593 | LPair<S, SS> matchFacts2(S pat) { |
594 | ret matchStrings2(pat, facts); |
595 | } |
596 | |
597 | // returns items too |
598 | LPair<S, SS> matchStrings2(S pat, Iterable<S> items) { |
599 | new LPair<S, SS> out; |
600 | for (S s : items) { |
601 | SS map = zipIt_deBracket(pat, s); |
602 | if (map != null) |
603 | out.add(pair(s, map)); |
604 | } |
605 | ret out; |
606 | } |
607 | |
608 | LS matchFacts(S var, S pat) { |
609 | ret map(matchFacts(pat), map -> map.get(var)); |
610 | } |
611 | |
612 | // pat = pattern with variables |
613 | // results are mappings with debracketed values |
614 | L<SS> matchFacts_keepBrackets(S pat) { |
615 | new L<SS> out; |
616 | for (S fact : facts) { |
617 | SS map = zipIt_keepBrackets(pat, fact); |
618 | if (map != null) |
619 | out.add(map); |
620 | } |
621 | ret out; |
622 | } |
623 | |
624 | void openAllTheories { |
625 | for (SS map : matchFacts_keepBrackets("theory $x $y")) |
626 | openTheory(tok_deRoundOrCurlyBracket(map.get("$x")), map.get("$y")); |
627 | } |
628 | |
629 | void openTheory(S name) { |
630 | for (SS map : matchFacts_keepBrackets("theory $x $y")) |
631 | if (eqic(properUnquote(tok_deRoundBracket($x(map))), name)) |
632 | ret with openTheory(name, $y(map)); |
633 | fail("Theory not defined: " + quote(name)); |
634 | } |
635 | |
636 | void openTheory(S name, S body) { |
637 | //print("Raw theory: " + quote(s)); |
638 | loadProgram(withoutLeadingLinesEmptyAfterTrim_autoUnindent(tok_deRoundOrCurlyBracket_keepFirstSpacing(body))); |
639 | if (verbose) print("Opened theory " + name); |
640 | } |
641 | |
642 | void autoOpenTheories { |
643 | onFactDo_keepBrackets("theory $x $y", (map, env) -> openTheory(tok_deRoundOrCurlyBracket(map.get("$x")), map.get("$y"))); |
644 | } |
645 | |
646 | // returns number of expectations checked |
647 | int checkExpectations() { |
648 | int n = 0; |
649 | // check if all expect (...) facts are met |
650 | for (SS map : matchFacts("expect $x")) { |
651 | assertContains(facts, firstValue(map)); |
652 | ++n; |
653 | } |
654 | // check if all don't expect (...) facts are met |
655 | for (SS map : matchFacts("don't expect $x")) { |
656 | assertDoesntContain(facts, firstValue(map)); |
657 | ++n; |
658 | } |
659 | ret n; |
660 | } |
661 | |
662 | void standardImports() { |
663 | if (standardImportsLoaded) ret; |
664 | set standardImportsLoaded; |
665 | registerImport("math", () -> philosophyBot1_math(this)); |
666 | registerImport("bool", () -> philosophyBot1_bool(this)); |
667 | registerImport("or", () -> philosophyBot1_orHandler(this)); |
668 | registerImport("iota", () -> philosophyBot1_iotaHandler(this)); |
669 | registerImport("tlft_honoringBrackets", () -> |
670 | addNativePredicate("tlft_honoringBrackets $x", |
671 | map -> printIf(verbose, "tlft output", |
672 | tlft_honoringBrackets($x(map))))); |
673 | addNativePredicate("printNonMatches", () -> { printNonMatches = true; true; }); |
674 | |
675 | philosophyBot1_enableAddSimplifier(this); |
676 | } |
677 | |
678 | void addFactPreprocessor(IPred<S> f) { |
679 | factPreprocessors.add(f); |
680 | } |
681 | |
682 | void addLogicRulePreprocessor(IPred<LogicRule> f) { |
683 | logicRulePreprocessors.add(f); |
684 | } |
685 | |
686 | void registerImport(S name, Runnable handler) { |
687 | S line = "import " + name; |
688 | factPreprocessors.add(s -> { |
689 | if (eqic(s, line)) { |
690 | if (verbose) print("Importing " + name); |
691 | handler.run(); |
692 | true; |
693 | } |
694 | false; |
695 | }); |
696 | } |
697 | |
698 | bool hasFact(S fact) { |
699 | ret contains(facts, fact); |
700 | } |
701 | |
702 | bool hasContradiction() { ret hasFact("contradiction"); } |
703 | |
704 | LS mainTokenize(S s) { |
705 | ret javaTokWithBrackets(s); |
706 | } |
707 | |
708 | // sanitize untrusted input - overly safe version |
709 | S sanitizeInput(S s) { |
710 | ret joinWithSpace(antiFilter(words2_plusApostrophe(s), w -> isVar(w))); |
711 | } |
712 | |
713 | void deleteFacts(Iterable<S> l) { |
714 | Set<S> set = asCISet(l); |
715 | facts = filterCISet(facts, f -> !contains(set, f)); |
716 | } |
717 | |
718 | Cl<S> factsDeduced() { |
719 | ret listMinusList(facts, originalFacts); |
720 | } |
721 | |
722 | bool containsDollarVars(O o) { |
723 | // abuse transform function |
724 | new Flag flag; |
725 | withCancelPoint(cp -> { |
726 | transform(x -> { |
727 | if (x cast S) { |
728 | if (main containsDollarVars(x)) { |
729 | flag.raise(); |
730 | cancelTo(cp); |
731 | } |
732 | ret x; |
733 | } |
734 | null; |
735 | }, o); |
736 | }); |
737 | ret flag!; |
738 | } |
739 | |
740 | L<LogicRule> allLogicRulesWithoutLHSVars() { |
741 | ret filter(logicRules, r -> !containsDollarVars(leftmostCondition(r.lhs))); |
742 | } |
743 | |
744 | O leftmostCondition(O o) { |
745 | while (o instanceof And) o = ((And) o).a; |
746 | ret o; |
747 | } |
748 | |
749 | void _standardHandlers { |
750 | philosophyBot_autoOpenTheoriesHandler(this); |
751 | addFactPreprocessor(s -> { if (eqic(s, "standard imports")) ret true with standardImports(); false; }); |
752 | } |
753 | |
754 | void runAndCheckExpectations { |
755 | run(); |
756 | checkExpectations(); |
757 | } |
758 | |
759 | void addDeepTransformer(IF1<S> transformer) { |
760 | if (deepTransformers == null) { |
761 | deepTransformers = new L; |
762 | // enable transformers |
763 | anyCodeOnFacts.newA(fact -> |
764 | addFactWithTrail(gazelle_deepTransform( |
765 | s -> firstTransformersResult(deepTransformers, s), fact), |
766 | trails == null ? null : new TTransformed(fact, transformer))); |
767 | } |
768 | deepTransformers.add(transformer); |
769 | } |
770 | |
771 | O getExtension(O key) { ret mapGet(extensions, key); } |
772 | |
773 | void addExtension(O key, O value) { |
774 | if (extensions == null) extensions = new Map; |
775 | extensions.put(key, value); |
776 | } |
777 | |
778 | void enableTrails() { if (trails == null) trails = ciMap(); } |
779 | |
780 | O getTrail(S fact) { ret mapGet(trails, fact); } |
781 | |
782 | void printDeducedFactsWithTrails() { |
783 | printAsciiHeading("Deduced facts with trails"); |
784 | for (S fact : factsDeduced()) { |
785 | print(fact); |
786 | printUnlessNull(" << ", getTrail(fact)); |
787 | } |
788 | } |
789 | } |
Began life as a copy of #1025597
download show line numbers debug dex old transpilations
Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
Snippet ID: | #1027175 |
Snippet name: | PhilosophyBot1 (backup before trails 2) |
Eternal ID of this version: | #1027175/1 |
Text MD5: | 5c4f33bceecbb530d384bd9f65e781aa |
Transpilation MD5: | 3486156abffc500c92eb7767e43952dc |
Author: | stefan |
Category: | |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2020-02-24 11:35:00 |
Source code size: | 24093 bytes / 789 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 164 / 233 |
Referenced in: | [show references] |