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