Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

431
LINES

< > BotCompany Repo | #1017587 // NLLogicChecker_v2

JavaX fragment (include)

1  
sclass NLLogicChecker_v2 {
2  
  S input;
3  
  new L<S> facts;
4  
  new L<IfThen> rules;
5  
  StringMatcher matcher = ai_standardMatcher();
6  
  new L<S> posted;
7  
  new ThreadLocal<IfThen> checkingRule;
8  
  VF2<O, Matching> onChecking; // first arg: IfThen or Exp
9  
  VF3<O, Matching, O> onChecked; // first arg: IfThen or Exp, last arg: Bool or Throwable
10  
  static bool staticVerbose;
11  
  bool useIterate, allowUnsafeEvals = true;
12  
  new HashMap<S, FuncChecker> funcCheckers;
13  
  new HashMap<S, FuncIterator> funcIterators;
14  
  S followingUpOn;
15  
16  
  List<Map> recentHistory;
17  
  L<S> entities;
18  
  F2<Exp, Matching, O> evaluator = func(Exp e, Matching m) {
19  
    S code = e.text();
20  
    if (!allowUnsafeEvals && !isSafeCodeFragment(code)) null;
21  
    ret nlLogic_evalExp(NLLogicChecker_v2.this, code, m);
22  
  };
23  
  
24  
  abstract sclass FuncChecker {
25  
    abstract bool check(Func e, Matching m);
26  
  }
27  
28  
  abstract sclass FuncIterator {
29  
    abstract void iterate(Func e, Matching m, Runnable onMatch);
30  
  }
31  
32  
  sclass Matching {
33  
    new VarMatches matches; // var -> string value
34  
    new L<Exp> output;
35  
    //L<RuleFailInfo> ruleFails;
36  
    bool verbose = staticVerbose;
37  
    
38  
    toString { ret sfu(matches) + "/" + sfu(output); }
39  
  }
40  
  
41  
  bool checkRule(final IfThen rule, final Matching m) {
42  
    if (rule == null) false;
43  
    ret logCheck(rule, m, func -> Bool { checkRule_impl(rule, m) });
44  
  }
45  
  
46  
  bool checkRule_impl(IfThen rule, Matching m) {
47  
    temp tempSetThreadLocal(checkingRule, rule);
48  
    if (!checkExpression(rule.in, m)) false;
49  
    m.output.add(apply(rule.out, m));
50  
    true;
51  
  }
52  
  
53  
  // returns (success, remaining conditions)
54  
  Pair<Bool, Exp> checkFirstCondition(IfThen rule, Matching m) {
55  
    temp tempSetThreadLocal(checkingRule, rule);
56  
    ret checkFirstCondition(rule.in, m);
57  
  }
58  
  
59  
  Pair<Bool, Exp> checkFirstCondition(Exp exp, Matching m) {
60  
    Pair<Exp> p = nlLogic_extractFirstCondition(exp);
61  
    if (p == null) ret pair(true, null);
62  
    if (!checkExpression(p.a, m)) ret pair(false, null);
63  
    ret pair(true, p.b);
64  
  }
65  
  
66  
  IfThen apply(IfThen r, Matching m) {
67  
    ret r == null ? null : IfThen(apply(r.in, m), apply(r.out, m));
68  
  }
69  
  
70  
  Exp apply(Exp e, Matching m) {
71  
    ret apply(e, m.matches);
72  
  }
73  
  
74  
  Exp apply(Exp e, SS m) {
75  
    if (e == null) null;
76  
    if (e cast And)
77  
      ret And(apply(e.a, m), apply(e.b, m));
78  
    if (e cast ExpNot)
79  
      ret ExpNot(apply(e.a, m));
80  
    if (e cast Func) {
81  
      if (contains(e.options, 'javaTokNoQuotes) && e.arg instanceof Sentence2)
82  
        ret Func(e.name, Sentence2(join(replaceVars_withDollarQ(javaTokNoQuotes(e.arg.text()), m))));
83  
      else
84  
        ret Func(e.name, apply(e.arg, m));
85  
    }
86  
      
87  
    if (e cast Sentence)
88  
      ret Sentence(javaTok(matcher.apply(e.text(), m)));
89  
    if (e cast Sentence2)
90  
      ret Sentence2(matcher.apply(e.text(), m));
91  
      
92  
    ret e;
93  
  }
94  
  
95  
  <A> A logCheck(O o, Matching m, F0<A> f) {
96  
    callF(onChecking, o, m);
97  
    try {
98  
      A result = callF(f);
99  
      callF(onChecked, o, m, result);
100  
      ret result;
101  
    } catch e {
102  
      callF(onChecked, o, m, e);
103  
      throw rethrow(e);
104  
    }
105  
  }
106  
  
107  
  final bool checkExpression(final Exp e, final Matching m) {
108  
    ret logCheck(e, m, func -> Bool { checkExpression_impl(e, m) });
109  
  }
110  
  
111  
  bool checkExpression_impl_1(Exp e, Matching m) {
112  
    if (e cast And)
113  
      ret checkExpression(e.a, m) && checkExpression(e.b, m);
114  
    ret checkExpression_single(e, m);
115  
  }
116  
  
117  
  bool checkExpression_single(Exp e, Matching m) {
118  
    if (e cast ExpNot) {
119  
      temp tempBackupMatches(m);
120  
      ret !checkExpression(e.a, m);
121  
    }
122  
    if (e cast Func) {
123  
      if (eq(e.name, 'input) && !cic(e.options, 'flexMatch)) {
124  
        S pat = nlLogic_text(e.arg);
125  
        if (contains(e.options, 're)) // regular expression
126  
          ret regexpFindIC(pat, input);
127  
          
128  
        ret nlLogic_matchVBarPattern(this, pat, input, m);
129  
      } else if (eq(e.name, "fact")) {
130  
        S pat = nlLogic_text(e.arg);
131  
        if (contains(e.options, "random"))
132  
          ret nlLogic_matchRandomFact(this, pat, m);
133  
        else
134  
          ret nlLogic_matchAnyFact(this, pat, m);
135  
      } else if (eq(e.name, "allFacts")) {
136  
        S pat = nlLogic_text(e.arg);
137  
        L<VarMatches> l = nlLogic_matchAllFacts(this, pat, m);
138  
        for i over l: {
139  
          SS vars = reverseGet(l, i); // facts are normally reversed, so re-reverse to get them in order
140  
          int n = i+1;
141  
          for (S var, value : vars) {
142  
            if (!strictPutIC(m.matches, var + n, value)) false;
143  
          }
144  
        }
145  
        true;
146  
      }
147  
    }
148  
    false;
149  
  }
150  
  
151  
  AutoCloseable tempBackupMatches(final Matching m) {
152  
    final VarMatches oldMatches = new (m.matches);
153  
    ret autocloseable { m.matches = oldMatches; };
154  
  }
155  
  
156  
  O evalExp(Exp e, Matching m) {
157  
    ret callF(evaluator, e, m);
158  
  }
159  
  
160  
  bool checkExpression_impl(Exp e, Matching m) {
161  
    new Matches mm;
162  
    if (e cast Func) {
163  
      // FUNCTION CONDITIONS
164  
      
165  
      FuncChecker checker = funcCheckers.get(e.name);
166  
      if (checker != null && checker.check(e, m)) true;
167  
      
168  
      if (eq(e.name, "singular"))
169  
        ret nlLogic_stringFunction(f singular, e, m.matches);
170  
      else if (eq(e.name, 'entity)) {
171  
        if (entities == null) {
172  
          long time = sysNow();
173  
          fS switched = switcheroo(input);
174  
          print("Switched >> " + switched);
175  
          entities = evalWithTimeoutOrNull(5000, func -> LS {
176  
            mapMethod('text, ai_extractEntities_v1(switched))
177  
          });
178  
          print("Entities (" + elapsedMS(time) + " ms): " + joinWithComma(entities));
179  
          if (entities == null) entities = new L;
180  
        }
181  
        for (S entity : entities)
182  
          if (matcher.match(nlLogic_text(e.arg), entity, m.matches)) true;
183  
      } else if (startsWith(e.name, "line", mm) && isInteger(mm.rest()) && checkingRule! != null) {
184  
        int n = parseInt(mm.rest())-nlLogic_numberOfLinesReferenced(checkingRule->in);
185  
        S line = n == 0 ? input : getString(get(recentHistory, l(recentHistory)+n), 'text);
186  
        //print("Recent: " + recentHistory);
187  
        S pat = e.arg.text();
188  
        //print("n=" + n + ", Matching " + e + " with " + line);
189  
        ret matcher.match(pat, line, m.matches);
190  
      } else if (eq(e.name, 'iSaid)) {
191  
        S line = getString(last(recentHistory), 'text);
192  
        if (line == null) false;
193  
        ret matcher.match(e.arg.text(), line, m.matches);
194  
      } else if (eq(e.name, 'unknownIf)) {
195  
        S statement = nlLogic_text(apply(e.arg, m));
196  
        //print("Checking statement: " + statement);
197  
        ret !cic(facts, statement) && !cic(facts, "Untrue: " + statement);
198  
      } else if (eq(e.name, 'inputContainsTokens))
199  
        ret jcontains(input, nlLogic_text(e.arg));
200  
      else if (eq(e.name, 'inputStartsWith))
201  
        ret startsWith(input, nlLogic_text(e.arg));
202  
      else if (eq(e.name, 'anyInput))
203  
        ret nempty(input);
204  
      else if (eq(e.name, 'preciseInput))
205  
        ret eq(nlLogic_text(apply(e.arg, m)), input); // Incomplete var support
206  
      else if (eq(e.name, 'followingUpOn)) {
207  
        S text = nlLogic_text(e.arg);
208  
        if (eq(text, followingUpOn)) true;
209  
        
210  
        Map prevPrev = nextToLast(recentHistory);
211  
        S msgID = getString(prevPrev, 'globalID);
212  
        S input = getString(prevPrev, 'text);
213  
        
214  
        S ruleID = null, dollarInput = null;
215  
        
216  
        // e.g. "lhnshnhcklhabvmu with input=$input"
217  
        if (match("* with input=*", text, mm) && !isDollarVar(mm.get(1))) {
218  
          ruleID = mm.unq(0); dollarInput = mm.get(1);
219  
        } else
220  
          ruleID = text;
221  
          
222  
        //print("followingUpOn: msgID=" + msgID + ", input=" + input);
223  
        //printStruct(+prevPrev);
224  
        S pat = format("Rule * fired on message * ", ruleID, msgID);
225  
        //print("pat=" + pat);
226  
        for (S ruleFired : mL("Telegram Rule Fires"))
227  
          if (swic(ruleFired, pat)) {
228  
            if (dollarInput != null && !strictPutIC(m.matches, dollarInput, input)) false;
229  
            L<S> tok = javaTokWithBrackets2(ruleFired);
230  
            if (find3("with vars *", tok, mm)) {
231  
              SS vars = safeUnstructMap(mm.get(0));
232  
              if (!addMapToMapWithoutOverwritingIC(m.matches, vars)) false;
233  
            }
234  
            true;
235  
          }
236  
        false;
237  
      } else if (eq(e.name, 'debug))
238  
        ret true with print("[debug] " + apply(e.arg, m));
239  
    }
240  
    
241  
    if (e cast Eq) {
242  
      // EQUATION CONDITIONS
243  
      
244  
      Exp r = e.right;
245  
      S var = nlLogic_text(e.left);
246  
      
247  
      if (endsWith(var, "!")) { // $x != bla
248  
        temp tempBackupMatches(m);
249  
        ret !matcher.match(dropSuffixTrim("!", var), r.text(), m.matches);
250  
      }
251  
      
252  
      if (r cast Func) pcall {
253  
        if (eq(r.name, 'eval)) {
254  
          O result = evalExp(r.arg, m);
255  
          if (result != null) { // Not allowing null results anymore
256  
            LS vars = tok_splitAtComma(var);
257  
258  
            Bool x = ai_matchObjectWithMultipleVars(vars, result, m.matches);
259  
            if (x != null) ret x;
260  
              
261  
            S sResult = str(result);
262  
            StringMatcher _matcher = matcher;
263  
            if (isDollarVar(var)) _matcher = new NLStringMatcher_singleDollarVar;
264  
            else if (contains(var, ',')) { // TODO: use Pair instead - there is only like one rule using this
265  
              if (allDollarVars(vars)
266  
                && ai_matchMulti(vars, tok_splitAtComma(sResult), m.matches)) true;
267  
            }
268  
              
269  
            ret _matcher.match(var, sResult, m.matches);
270  
          }
271  
        }
272  
      }
273  
    }
274  
    
275  
    if (e cast Sentence2) {
276  
      // SENTENCE CONDITIONS
277  
      
278  
      S text = e.text();
279  
      if (eq(text, 'true))
280  
        true;
281  
    }
282  
    
283  
    ret checkExpression_impl_1(e, m);
284  
  }
285  
286  
  void iterate(final Exp e, final Matching m, final Runnable onMatch) {
287  
    if (e cast And) {
288  
      iterate(e.a, m, r { iterate(e.b, m, onMatch) });
289  
      ret;
290  
    }
291  
    
292  
    if (e cast ExpNot) {
293  
      if (m.verbose) print("iterate not: " + e);
294  
      final new Flag flag;
295  
      withCancelPoint(voidfunc(final CancelPoint cp) {
296  
        iterate(e.a, m, r {
297  
          if (m.verbose) print("iterate not: raising flag");
298  
          flag.raise();
299  
          cancelTo(cp);
300  
        });
301  
      });
302  
      if (!flag.isUp())
303  
        callF(onMatch);
304  
      ret;
305  
    }
306  
      
307  
    iterate_single(e, m, onMatch);
308  
  }
309  
310  
  void iterate_single(final Exp e, final Matching m, final Runnable onMatch) {
311  
    if (e cast Func) {
312  
      //print("Checking func iterators: " + e.name);
313  
      FuncIterator it = funcIterators.get(e.name);
314  
      if (it != null)
315  
        it.iterate(e, m, onMatch);
316  
      
317  
      if (eq(e.name, 'fact)) {
318  
        S pat = nlLogic_text(e.arg);
319  
        VarMatches oldMatches = new(m.matches);
320  
        for (S fact : facts) {
321  
          if (m.verbose)
322  
            print("iterate matching: " + pat + " with " + fact + " - " + sfu(m.matches));
323  
          for (S pat2 : tok_splitAtVerticalBar(pat))
324  
            if (matcher.match(pat2, fact, m.matches)) {
325  
              if (m.verbose)
326  
                print("iterate match: " + pat + " / " + fact + " - " + m);
327  
              try { callF(onMatch); } finally { m.matches = new VarMatches(oldMatches); }
328  
            }
329  
        }
330  
        ret;
331  
      } else if (eq(e.name, "input") && cic(e.options, 'flexMatch)) {
332  
        S pat = nlLogic_text(e.arg);
333  
        if (m.verbose)
334  
          print("input flexMatch " + pat);
335  
          
336  
        VarMatches oldMatches = new(m.matches);
337  
        nlLogic_flexMatch_iterate_vbar(pat, input, m, onMatch, oldMatches);
338  
        ret;
339  
      }
340  
    }
341  
    
342  
    if (e instanceof Sentence2 && contains(e.text(), " in ")) {
343  
      L<S> tok = javaTokPlusAllThreeBrackets(e.text());
344  
      S var, var2;
345  
      new Matches mm;
346  
      if (m.verbose)
347  
        print("iterate in eval tok: " + sfu(tok)); 
348  
        
349  
      if (jmatch("* in eval *", tok, mm) && isDollarVar(var = mm.get(0)) && isRoundBracketed(mm.get(1))) {
350  
        if (m.verbose)
351  
          print("iterate in eval: " + mm.get(1)); 
352  
        Iterable l = cast evalExp(Sentence2(deRoundBracket(mm.get(1))), m);
353  
        VarMatches oldMatches = new(m.matches);
354  
355  
        for (O element : unnull(l)) {
356  
          continue unless element != null;
357  
          S s = str(element);
358  
          if (m.verbose) print("iterate in eval got element: " + s);
359  
          if (strictPutIC(m.matches, var, s))
360  
            try { callF(onMatch); } finally { m.matches = new VarMatches(oldMatches); }
361  
        }
362  
      }
363  
      
364  
      if (jmatch("*, * in eval *", tok, mm) && isDollarVar(var = mm.get(0)) && isDollarVar(var2 = mm.get(1)) && isRoundBracketed(mm.get(2))) {
365  
        LS vars = ll(var, var2);
366  
        Iterable l = cast evalExp(Sentence2(deRoundBracket(mm.get(2))), m);
367  
        VarMatches oldMatches = new(m.matches);
368  
369  
        for (O element : unnull(l)) {
370  
          continue unless element != null;
371  
          if (m.verbose) print("iterate in eval got element: " + element);
372  
          if (isTrue(ai_matchObjectWithMultipleVars(vars, element, m.matches)))
373  
            try { callF(onMatch); } finally { m.matches = new VarMatches(oldMatches); }
374  
        }
375  
      }
376  
    }
377  
    
378  
    temp tempBackupMatches(m);
379  
    if (m.verbose)
380  
      print("iterate fallback: " + sfu(e)); 
381  
    if (checkExpression(e, m)) {
382  
      if (m.verbose)
383  
        print("iterate fallback match: " + e); 
384  
      callF(onMatch);
385  
    }
386  
  }
387  
  
388  
  bool checkHelper(Exp e, Matching m) {
389  
    ret nlLogic_checkHelper(e, m.matches);
390  
  }
391  
  
392  
  *() {
393  
    initCheckers();
394  
    initIterators();
395  
  }
396  
  
397  
  void initCheckers {
398  
    mapPutMultipleKeys(funcCheckers, new FuncChecker {
399  
      bool check(Func e, Matching m) {
400  
        ret nlLogic_stringFunction(f ai_verbPhraseFromThirdPerson, e, m.matches);
401  
      }
402  
    }, 'verbPhraseFromThirdPerson, 'verbFromThirdPerson);
403  
    
404  
    funcCheckers.put('eval, new FuncChecker {
405  
      bool check(Func e, Matching m) {
406  
        ret eq("true", str(evalExp(e.arg, m)));
407  
      }
408  
    });
409  
  }
410  
  
411  
  void initIterators {
412  
    funcIterators.put('phrase, new FuncIterator {
413  
      void iterate(Func e, Matching m, Runnable onMatch) {
414  
        //if (!contains(e.options, 'words)) ret;
415  
        S pat = e.argText();
416  
        LS patTok = standardTok(pat);
417  
        LS inputTok = standardTok(input);
418  
        
419  
        // optimizable
420  
        for (LS inputPart : tok_marchPatternThroughInput(patTok, inputTok))
421  
          if (matcher.match(pat, join(inputPart), m.matches))
422  
            callF(onMatch);
423  
      }
424  
    });
425  
  }
426  
  
427  
  // TODO: cache
428  
  LS standardTok(S s) {
429  
    ret javaTokWithAllBrackets(s);
430  
  }
431  
}

Author comment

Began life as a copy of #1017580

download  show line numbers  debug dex  old transpilations   

Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1017587
Snippet name: NLLogicChecker_v2
Eternal ID of this version: #1017587/126
Text MD5: 8c896eea64cfd6f47c89910275787351
Author: stefan
Category: javax / a.i.
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2018-12-04 17:06:30
Source code size: 14832 bytes / 431 lines
Pitched / IR pitched: No / No
Views / Downloads: 611 / 1370
Version history: 125 change(s)
Referenced in: [show references]