1 | // adapters are immutable! (plus returns a modified clone) |
2 | abstract sclass Adapter { |
3 | abstract bool canMatch(S in, S out); |
4 | Adapter plus(S in, S out) { ret this; } |
5 | S get(S in) { ret in; } |
6 | double size() { ret 0; } |
7 | } |
8 | |
9 | abstract sclass GenericAdapter { |
10 | void modify(OccTree2 node) {} |
11 | } |
12 | |
13 | // node in flight (+ optional adapter) |
14 | sclass InFlight { |
15 | OccTree2 node; |
16 | Adapter adapter; |
17 | |
18 | *(OccTree2 *node) {} |
19 | *(OccTree2 *node, Adapter *adapter) {} |
20 | |
21 | E adapted() { |
22 | // TODO: security when rewriting states |
23 | ret adapter == null ? node.e : new E(adapter.get(node.e.text()), node.e.type()); |
24 | } |
25 | } |
26 | |
27 | sclass LooseBot { |
28 | sbool debug, repeat = true; |
29 | OccTree2 tree; |
30 | new L<InFlight> nodes; |
31 | new L<L> rewindStack; |
32 | O newAdapter; |
33 | O grabber; // func(S -> E) |
34 | GenericAdapter genericAdapter; |
35 | |
36 | // WordAdapter now default |
37 | *(OccTree2 tree) { this(tree, func { new WordAdapter }); } |
38 | |
39 | // main constructor |
40 | *(OccTree2 *tree, O *newAdapter) { |
41 | expandEllipsis(tree); |
42 | } |
43 | |
44 | *(S theme) { this(makeOccTree(theme)); } |
45 | *(S theme, O newAdapter) { this(makeOccTree(theme), newAdapter); } |
46 | |
47 | Adapter makeAdapter() { |
48 | ret newAdapter == null ? null : (Adapter) call(newAdapter); |
49 | } |
50 | |
51 | void take(E in) { |
52 | remember(); |
53 | |
54 | // try starting over from beginning of tree too |
55 | if (repeat) setAdd(nodes, new InFlight(tree, makeAdapter())); |
56 | |
57 | new L<InFlight> l; |
58 | |
59 | // try grabber |
60 | if (grabber != null && in.q()) try { |
61 | E grabbed = cast callFunction(grabber, in.text()); |
62 | if (grabbed != null) { |
63 | if (debug) |
64 | print("Grabber worked! " + in.text() + " => " + grabbed); |
65 | |
66 | // make a mini tree with Q + A so it is matched in |
67 | // next call to getSingleOutput() |
68 | OccTree2 node = new OccTree2(in); |
69 | node.next.add(new OccTree2(grabbed)); |
70 | |
71 | l.add(new InFlight(node)); |
72 | } else |
73 | if (debug) |
74 | print("Grabber didnt't return anything. " + in.text()); |
75 | } catch e { |
76 | if (debug) printStackTrace(e); |
77 | } |
78 | |
79 | for (InFlight flight : nodes) |
80 | for (OccTree2 n : flight.node.next) { |
81 | if (genericAdapter != null) |
82 | genericAdapter.modify(n); |
83 | if (eq(n.e.type(), in.type()) && (flight.adapter != null |
84 | ? flight.adapter.canMatch(n.e.text(), in.text()) |
85 | : matchE(n.e, in))) { |
86 | l.add(new InFlight(n, flight.adapter == null ? null |
87 | : flight.adapter.plus(n.e.text(), in.text()))); |
88 | } |
89 | } |
90 | |
91 | nodes = l; |
92 | } |
93 | |
94 | L<E> possibleNextInput() { |
95 | new HashSet<E> l; |
96 | if (repeat) l.add(tree.e); |
97 | |
98 | L<InFlight> ns = cloneList(nodes); |
99 | if (repeat) setAdd(ns, new InFlight(tree, makeAdapter())); |
100 | for (InFlight flight : ns) |
101 | for (OccTree2 n : flight.node.next) |
102 | l.add(new InFlight(n, flight.adapter).adapted()); |
103 | ret asList(l); |
104 | } |
105 | |
106 | void remember() { |
107 | if (rewindStack != null) |
108 | rewindStack.add(cloneList(nodes)); |
109 | } |
110 | |
111 | E getSingleOutput() { |
112 | remember(); |
113 | new L<InFlight> l; |
114 | for (InFlight flight : nodes) |
115 | for (OccTree2 n : flight.node.next) |
116 | if (n.e.a() || isCommand(n.e)) |
117 | l.add(new InFlight(n, flight.adapter)); |
118 | if (empty(l)) { rewind(); null; } |
119 | nodes = l; |
120 | ret first(nodes).adapted(); |
121 | } |
122 | |
123 | void rewind() { |
124 | nodes = popLast(rewindStack); |
125 | } |
126 | |
127 | bool isCommand(E e) { |
128 | ret e.state() && matchStart("bot", e.state); |
129 | } |
130 | |
131 | void noRewind() { |
132 | rewindStack = null; |
133 | } |
134 | |
135 | bool matchE(E a, E b) { |
136 | // standard NL matching |
137 | ret eq(a.type(), b.type()) && match(a.text(), b.text()); |
138 | } |
139 | |
140 | S nodesToString(L<InFlight> nodes) { |
141 | new L<S> l; |
142 | l.add(n(l(nodes), "node")); |
143 | for (InFlight flight : nodes) { |
144 | l.add(str(flight.node.e)); |
145 | if (flight.adapter != null) |
146 | l.add(" " + flight.adapter); |
147 | } |
148 | ret rtrim(fromLines(l)); |
149 | } |
150 | |
151 | S thoughts() { |
152 | new L<S> l; |
153 | l.add("Expecting input:\n"); |
154 | for (E e : possibleNextInput()) |
155 | if (e != null) |
156 | l.add(" " + e); |
157 | l.add(""); |
158 | l.add(nodesToString(nodes)); |
159 | if (rewindStack != null) { |
160 | l.add("\nHistory\n"); |
161 | for (L<InFlight> nodes : reversedList(rewindStack)) |
162 | l.add(indent(nodesToString(nodes))); |
163 | } |
164 | ret fromLines(l); |
165 | } |
166 | |
167 | LooseBot debugOn() { |
168 | debug = true; |
169 | ret this; |
170 | } |
171 | } |
172 | |
173 | sclass WordAdapter extends Adapter { |
174 | new Map<S, S> wordMap; |
175 | |
176 | L<S> tok(S s) { |
177 | ret nlTok2(dropPunctuation2(s)); |
178 | } |
179 | |
180 | bool canMatch(S in, S out) { |
181 | L<S> t1 = tok(in), t2 = tok(out); |
182 | ret l(t1) == l(t2); |
183 | } |
184 | |
185 | Adapter plus(S in, S out) { |
186 | L<S> t1 = tok(in), t2 = tok(out); |
187 | if (l(t1) != l(t2)) ret this; |
188 | |
189 | WordAdapter a = cast nuObject(getClass()); |
190 | a.wordMap = cloneMap(wordMap); |
191 | for (int i = 1; i < l(t1); i += 2) { |
192 | S w1 = t1.get(i), w2 = t2.get(i); |
193 | if (!eqic(w1, w2)) |
194 | // just overwrite - be flexible! |
195 | a.wordMap.put(w1.toLowerCase(), w2.toLowerCase()); |
196 | } |
197 | ret a; |
198 | } |
199 | |
200 | S get(S s) { |
201 | L<S> tok = nlTok2(s); |
202 | for (int i = 1; i < l(tok); i += 2) { |
203 | S w = lookupToken(tok.get(i)); |
204 | if (nempty(w)) |
205 | tok.set(i, w); |
206 | } |
207 | ret join(tok); |
208 | } |
209 | |
210 | S lookupToken(S s) { |
211 | ret wordMap.get(s.toLowerCase()); |
212 | } |
213 | |
214 | double size() { |
215 | ret l(wordMap); |
216 | } |
217 | |
218 | public S toString() { |
219 | ret structure(wordMap); |
220 | } |
221 | } |
222 | |
223 | sclass WordAdapter2 extends WordAdapter { |
224 | new Map<S, S> wordMap; |
225 | |
226 | L<S> tok(S s) { |
227 | ret nlTok2(s); |
228 | } |
229 | } |
Began life as a copy of #1003413
download show line numbers debug dex old transpilations
Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1003575 |
Snippet name: | LooseBot v6 (with generic adapters) |
Eternal ID of this version: | #1003575/1 |
Text MD5: | 0174bb8b912c2c411b624bfcc5bc9b0c |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-07-20 00:54:32 |
Source code size: | 5649 bytes / 229 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 568 / 533 |
Referenced in: | [show references] |