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