1 package acl2s.plugin.editors.session;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.EOFException;
6 import java.io.File;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.ObjectInputStream;
10 import java.io.ObjectOutputStream;
11 import java.io.Serializable;
12 import java.util.ArrayList;
13
14 import org.eclipse.jface.text.BadLocationException;
15 import org.eclipse.jface.text.DocumentEvent;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.IRegion;
18 import org.eclipse.jface.text.ITypedRegion;
19 import org.eclipse.jface.text.Region;
20 import org.eclipse.swt.SWT;
21
22 import acl2s.lib.parse.ParseException;
23 import acl2s.lib.parse.StringParser;
24 import acl2s.lib.parse.obj.LispObject;
25 import acl2s.lib.parse.obj.Sym;
26 import acl2s.lib.session.IEnvInfo;
27 import acl2s.lib.session.IResultInfo;
28 import acl2s.lib.session.IStatusInfo;
29 import acl2s.lib.session.MyInteractiveSessionConfig;
30 import acl2s.lib.session.SessionDeadException;
31 import acl2s.lib.session.SessionException;
32 import acl2s.lib.session.SessionMode;
33 import acl2s.lib.session.SessionStateException;
34 import acl2s.plugin.Acl2sPlugin;
35 import acl2s.plugin.IPeerDocument;
36 import acl2s.plugin.ISessionDocument;
37 import acl2s.plugin.editors.A2sDocument;
38 import acl2s.plugin.editors.A2sEditor;
39 import acl2s.plugin.editors.AbstractDocumentPartitioner;
40 import acl2s.plugin.editors.MyDocumentProvider;
41 import acl2s.plugin.editors.MyTypedRegion;
42 import acl2s.plugin.editors.lisp.LineMode;
43 import acl2s.plugin.prefs.Acl2Prefs;
44 import acl2s.plugin.prefs.InteractionPrefs;
45 import acl2s.plugin.prefs.SessionPrefs;
46 import acl2s.uilib.cmd.BadCmdException;
47 import acl2s.uilib.cmd.ResolvableUserInput;
48 import acl2s.uilib.cmd.ResolvedInput;
49 import acl2s.uilib.cmd.UnresolvedKeywordCmd;
50 import acl2s.uilib.cmd.WormholeWrappedInput;
51 import acl2s.uilib.session.IInputInfo;
52 import acl2s.uilib.session.ISessionClient;
53 import acl2s.uilib.session.ISessionModel;
54 import acl2s.uilib.session.ISessionStatusListener;
55 import acl2s.uilib.session.InteractiveSessionManager;
56 import acl2s.uilib.session.StartupInputAndEnv;
57
58 public class SessionDocument extends A2sDocument
59 implements ISessionModel, ISessionDocument, ISessionClient, ISessionStatusListener {
60 public static final String ID = SessionDocument.class.getCanonicalName();
61
62 protected static final char versionId = 19;
63
64 protected IPeerDocument peer = null;
65 protected MyInteractiveSessionConfig config = null;
66 protected InteractiveSessionManager session = null;
67
68 protected Partitioner partitioner;
69
70 protected CurElement cur;
71 protected final ArrayList<DoneElement> done;
72 protected int dumpLength;
73 protected int newDumpLength;
74
75 protected final ArrayList<Integer> inputIdxs;
76 protected final ArrayList<Integer> checkpointIdxs;
77
78 protected final ArrayList<String> cmdHistory;
79 protected int cmdPos;
80 protected final ArrayList<String> miscHistory;
81 protected int miscPos;
82
83 public SessionDocument(MyDocumentProvider dp) {
84 super(dp);
85
86 //setTextStore(new StringBuilderTextStore());
87
88 session = new InteractiveSessionManager(Acl2sPlugin.getDefault(),this,this);
89
90 done = new ArrayList<DoneElement>();
91 inputIdxs = new ArrayList<Integer>();
92 checkpointIdxs = new ArrayList<Integer>();
93
94 cmdHistory = new ArrayList<String>();
95 cmdHistory.add("");
96 cmdPos = 0;
97 miscHistory = new ArrayList<String>();
98 miscHistory.add("");
99 miscPos = 0;
100
101 tokens = new SessionDocumentLispTokens();
102 tokens.connect(this);
103
104 session.addSessionStatusListener(this);
105
106 reset();
107 }
108
109 /*public void setInput(IFileEditorInput input) {
110 this.input = input;
111 }*/
112
113 public void setPeer(IPeerDocument p) {
114 peer = p;
115 config.setMode(getAcl2Mode());
116 }
117
118 public IPeerDocument getPeer() { return peer; }
119
120 public InteractiveSessionManager getManager() { return session; }
121
122 public ISessionModel getModel() { return this; }
123
124 //public int getDumpLength() { return dumpLength; }
125
126 public int getNewDumpLength() { return newDumpLength; }
127
128 public boolean appendingDump() { return newDumpLength > dumpLength; }
129
130 public String getImmediate() {
131 return get2(dumpLength+1,getLength()-dumpLength-1);
132 }
133
134 public int readOnlyPoint() { return dumpLength + 1; }
135
136 public boolean allowReplace(int pos, int length, String text) {
137 // currently dumping I/O
138 if (appendingDump()) return true;
139
140 // otherwise, status must be ready for input
141 int status = session.getStatus();
142 if (status != READY_CMD_SESSION && status != READY_MISC_SESSION) return false;
143
144 // allow if in immediate region
145 return (pos > dumpLength) ||
146
147 // allow if updating separator & immediate (see UpdateSeparatorStrategy)
148 (pos == dumpLength && text.length() > 0 && Character.isWhitespace(text.charAt(0)));
149 }
150
151 public SessionDocumentProvider getProvider() {
152 return Acl2sPlugin.getA2sDocumentProvider();
153 }
154
155 /*
156 public File getProjectWorkingDir() {
157 IPath p = getOSPath();
158 IFile f = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(p);
159 if (f == null) { // not in a project; return containing dir
160 return p.toFile().getParentFile();
161 } else { // in a project; return project root
162 return f.getProject().getLocation().toFile();
163 }
164 }*/
165
166 public File getDesiredCBD() {
167 File me = getOSFile();
168 if (me == null) {
169 return new File(System.getProperty("user.dir")); // best we can do
170 } else {
171 return me.getParentFile();
172 }
173 }
174
175 public IInputInfo nextInputOption() {
176 if (peer != null) {
177 return peer.nextInputOption();
178 } else {
179 return null;
180 }
181 }
182
183 public void ping() {
184 session.ping();
185 }
186
187 public void commandCompleted(IInputInfo in, IStatusInfo status, int modelIdx) {
188 if (peer != null) {
189 peer.commandCompleted(in,status,modelIdx);
190 }
191 }
192
193
194
195 // description stuff
196 transient int cachedStatus = 0;
197
198 static final String[] descriptions = new String[] {
199 "(not running)",
200 "Starting up...",
201 "Ready for command input",
202 "Busy...",
203 "**Error in session**",
204 "Ready for non-command input"
205 };
206
207 protected String doGetDescription() {
208 String desc = "";
209 if (!peer.getLineMode().equals(LineMode.getDefault()))
210 {
211 desc = " (" + peer.getLineMode().getName() + ")";
212 }
213 return descriptions[cachedStatus] + " " + peer.getAcl2Mode().getName() + " Mode" + desc;
214 }
215
216 public void sessionStatusChanged(int status) {
|
At conditional (1): (status != this.cachedStatus): Taking true branch.
|
217 if (status != cachedStatus) {
218 cachedStatus = status;
219 updateDescriptions();
|
At conditional (2): (this.peer != null): Taking false branch.
|
|
At conditional (3): (status == 4): Taking true branch.
|
220 if (peer != null && status == NO_SESSION || status == ERROR_SESSION) {
|
Event deref_while_null: |
Dereferencing "this.peer" while this.peer=null. |
| Also see events: |
[branch_null] |
221 peer.resetLine();
222 }
223 }
224 resetUndoStuff();
225 }
226
227 // actions
228 public void cleanSession(A2sEditor ctx) {
229 session.killSession();
230 if (peer != null) {
231 peer.resetLine();
232 }
233 reset();
234 if (ctx instanceof SessionEditor) {
235 ctx.gotoEnd();
236 }
237 }
238
239 public void restartSession(A2sEditor ctx) {
240 SessionMode mode = getConfig().getMode();
241 if (mode != null && !mode.getUsable()) {
242 Acl2sPlugin.popupMessage("Session mode not installed",
243 "The session cannot be started because its mode, \"" +
244 mode.getName() + "\", is not installed under this Eclipse/ACL2s. To " +
245 "be able to start a session in this mode, you will need to install that mode. "+
246 "(Ask the person you got the file from.)",
247 SWT.ICON_WARNING);
248 } else {
249 String pref;
250 if (done.size() > 0) {
251 pref = SessionPrefs.getRestartPref(ctx.getEditorSite().getShell(), this, session.isAlive());
252 } else {
253 pref = SessionPrefs.RESTART_EXTEND;
254 }
255 if (pref == SessionPrefs.RESTART_CANCEL) {
256 return;
257 }
258 if (pref == SessionPrefs.RESTART_CLEAN) {
259 cleanSession(ctx);
260 } else {
261 session.killSession();
262 if (peer != null) {
263 peer.resetLine();
264 }
265 }
266 DoneElement d = cur.forceFinish();
267 done.add(d);
268 session.startNewSession(this,getConfig());
269 }
270 }
271
272 public void interruptSession(A2sEditor ctx) {
273 try {
274 getManager().interruptSession();
275 } catch (SessionDeadException e) {
276 // ignore
277 }
278 }
279
280 public void killSession(A2sEditor ctx) {
281 getManager().killSession();
282 }
283
284
285 public void forgetRedo(A2sEditor ctx) {
286 try {
287 /*(void)*/ session.systemCmd("(acl2s::clear-reverted-super-history acl2::state)");
288 cur.env.forgetRedo();
289 } catch (SessionStateException sse) {
290 ctx.errorMessageBox("Session busy", "Can't forget redo information while session is busy.");
291 }
292 }
293
294
295 /*====================== Saving/Loading =======================*/
296 public void reset() {
297 done.clear();
298 inputIdxs.clear();
299 checkpointIdxs.clear();
300 inputIdxs.add(Integer.valueOf(0));
301 checkpointIdxs.add(Integer.valueOf(0));
302
303 if (partitioner != null) {
304 partitioner.disconnect();
305 setDocumentPartitioner(null);
306 }
307 newDumpLength = 0;
308 set(" ");
309 dumpLength = 0;
310 partitioner = new Partitioner();
311 partitioner.connect(this);
312 setDocumentPartitioner(partitioner);
313
314 cmdPos = cmdHistory.size()-1;
315 miscPos = miscHistory.size()-1;
316
317 cur = new CurElement();
318 cur.connect(this);
319
320 if (peer != null) {
321 peer.resetLine();
322 }
323
324 if (config == null) {
325 config = new MyInteractiveSessionConfig(Acl2sPlugin.getBaseConfig(), Acl2sPlugin.getSessionSupportDir());
326 }
327 config.setMode(getAcl2Mode());
328
329 for (IProofTreeListener l : listeners) {
330 l.sessionCleaned();
331 }
332 }
333
334 // returns true if initially dirty
335 public void loadFrom(InputStream stream) {
336 ObjectInputStream in;
337 try {
338 try {
339 in = new ObjectInputStream(stream);
340 int x = in.readInt();
341 int m = x & 0xffff0000;
342 int v = x & 0xffff;
343 if (m != 0x0a250000) {
344 throw new ClassCastException("Invalid magic number for a2s file.");
345 }
346 if (v != versionId) {
347 throw new ClassCastException("Incompatible version number for a2s file.");
348 }
349 } catch (EOFException eofe) {
350 reset();
351 return; // just an empty file
352 }
353 if (partitioner != null) {
354 partitioner.disconnect();
355 setDocumentPartitioner(null);
356 }
357 set("");
358
359 String data = (String)in.readObject();
360 partitioner = (Partitioner) in.readObject();
361 config = (MyInteractiveSessionConfig) in.readObject();
362 config.setBaseConfig(Acl2sPlugin.getBaseConfig());
363 cur = (CurElement) in.readObject();
364 done.clear();
365 for (Object o : (Iterable<?>) in.readObject()) {
366 done.add((DoneElement) o);
367 }
368 dumpLength = in.readInt();
369 newDumpLength = dumpLength;
370 inputIdxs.clear();
371 for (Object o : (Iterable<?>) in.readObject()) {
372 inputIdxs.add((Integer) o);
373 }
374 checkpointIdxs.clear();
375 for (Object o : (Iterable<?>) in.readObject()) {
376 checkpointIdxs.add((Integer) o);
377 }
378 cmdHistory.clear();
379 for (Object o : (Iterable<?>) in.readObject()) {
380 cmdHistory.add((String) o);
381 }
382 cmdPos = in.readInt();
383 miscHistory.clear();
384 for (Object o : (Iterable<?>) in.readObject()) {
385 miscHistory.add((String) o);
386 }
387 miscPos = in.readInt();
388 in.close();
389
390 set(data);
391 partitioner.connect(this);
392 setDocumentPartitioner(partitioner);
393 cur.connect(this);
394 } catch (ClassCastException cce) {
395 Acl2sPlugin.logWarning("Data error while reading in session history. Discarding previous history.", cce);
396 reset();
397 ensureDirty();
398 return;
399 } catch (ClassNotFoundException e) {
400 Acl2sPlugin.logWarning("Data error while reading in session history. Discarding previous history.", e);
401 reset();
402 ensureDirty();
403 return;
404 } catch (IOException ioe) {
405 Acl2sPlugin.logWarning("I/O error while reading in session history. Discarding previous history.", ioe);
406 reset();
407 ensureDirty();
408 return;
409 }
410 }
411
412 public InputStream getDumpStream() {
413 try {
414 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
415 ObjectOutputStream out = new ObjectOutputStream(bytes);
416 out.writeInt(0x0a250000 + versionId);
417 out.writeObject(get());
418 out.writeObject(partitioner);
419 out.writeObject(config);
420 out.writeObject(cur);
421 out.writeObject(done);
422 out.writeInt(dumpLength);
423 out.writeObject(inputIdxs);
424 out.writeObject(checkpointIdxs);
425 out.writeObject(cmdHistory);
426 out.writeInt(cmdPos);
427 out.writeObject(miscHistory);
428 out.writeInt(miscPos);
429 out.close();
430 return new ByteArrayInputStream(bytes.toByteArray());
431 } catch (IOException e) {
432 Acl2sPlugin.logError("Error building session dump stream.", e);
433 return null;
434 }
435 }
436
437
438
439 /*===================== state building ======================*/
440 private void doProcessOutputLine(String s) {
441 if (s.length() == 0) return;
442 if (cur.inProofTree) {
443 int i = s.indexOf("#>\\>");
444 if (i >= 0) {
445 if (i > 0) {
446 doProcessOutputLine(s.substring(0,i) + '\n');
447 }
448 cur.endProofTree();
449 doProcessOutputLine(s.substring(i + 4));
450 } else {
451 doProcessOutputLine2(s);
452 }
453 } else {
454 if (s.startsWith("#<\\<0")) {
455 cur.startProofTree();
456 doProcessOutputLine(s.substring(5));
457 } else {
458 doProcessOutputLine2(s);
459 }
460 }
461 }
462
463 private void doProcessOutputLine2(String s) {
464 if (s.length() == 0) return;
465 if (s.endsWith("$\n")) {
466 /*if (s.endsWith("$ClAuSe{$\n")) {
467 // TODO: clause stuff
468 } else*/
469 if (s.startsWith("$ChEcKpOiNt{$") &&
470 s.endsWith("$ChEcKpOiNt}$\n")) {
471 cur.layDownCheckpoint(s.substring(13,s.length() - 14));
472 return;
473 }
474 }
475 cur.appendOutput(s);
476 }
477
478 public void appendOutputLine(String s) {
479 doProcessOutputLine(s);
480 cur.flushOutput();
481 }
482
483 public void appendOutputLines(Iterable<String> ss) {
484 for (String s: ss) {
485 doProcessOutputLine(s);
486 }
487 cur.flushOutput();
488 }
489
490 protected transient String savedCmd = null;
491
492 public int finishOutput(IStatusInfo statusInfo, IEnvInfo envInfo) {
493 DoneElement d = cur.finish(statusInfo);
494 done.add(d);
495 cur.init(envInfo);
496 replaceImmediate(cmdHistory.get(cmdPos));
497 return done.size() - 1;
498 }
499
500 public void updateLastEnv(IEnvInfo envInfo) {
501 cur.env = envInfo;
502 }
503
504 public void nextInput(IInputInfo in) {
505 cur.nextInput(in);
506 cmdHistory.set(cmdPos,getImmediate().trim());
507 replaceImmediate(miscHistory.get(miscPos));
508 }
509
510 public void newSession() {
511 cur.init(StartupInputAndEnv.instance);
512 cur.nextInput(StartupInputAndEnv.instance);
513 }
514
515
516 /*========================== accessing stuff ========================*/
517 public IEnvInfo getEnv(int idx) {
518 if (idx == done.size()) {
519 return cur.getEnv();
520 } else {
521 return done.get(idx).getEnv();
522 }
523 }
524
525 public IInputInfo getInput(int idx) {
526 if (idx == done.size()) {
527 return cur.getInput();
528 } else {
529 return done.get(idx).getInput();
530 }
531 }
532
533 public String getOutput(int idx) {
534 if (idx == done.size()) {
535 return cur.getOutput();
536 } else {
537 return done.get(idx).getOutput();
538 }
539 }
540
541 public String getProofTree(int idx) {
542 if (idx == done.size()) {
543 return cur.proofTree.toString();
544 } else {
545 return done.get(idx).getFinalProofTree();
546 }
547 }
548
549 public IStatusInfo getStatus(int idx) {
550 return done.get(idx).getStatus();
551 }
552
553
554 public int countCompletedCmds() {
555 return done.size();
556 }
557
558
559
560 public int findCheckpointOffset(int idx, String withGoal) {
561 int base = inputIdxs.get(idx).intValue();
562 int len = getLength();
563 try {
564 for (; base < len;) {
565 ITypedRegion r = getPartition(base);
566 if (r.getType().equals(OUTPUT)) break;
567 if (r.getType().equals(OUTPUTERR)) break;
568 base = r.getOffset() + r.getLength();
569 }
570 } catch (BadLocationException e1) {
571 // impossible
572 }
573
574 if (idx == done.size()) {
575 for (int i = 0; i < cur.chkptNames.size(); i++) {
576 if (withGoal.contains(cur.chkptNames.get(i)) &&
577 withGoal.contains(cur.chkptNames.get(i) + " ")) {
578 return base + cur.chkptOffsets.get(i).intValue();
579 }
580 }
581 return -1;
582 } else {
583 DoneElement e = done.get(idx);
584 for (int i = 0; i < e.chkptNames.length; i++) {
585 if (withGoal.contains(e.chkptNames[i]) &&
586 withGoal.contains(e.chkptNames[i] + " ")) {
587 return base + e.chkptOffsets[i];
588 }
589 }
590 return -1;
591 }
592 }
593
594
595 /*========================= misc ==========================*/
596 public SessionMode getAcl2Mode() {
597 if (peer != null) {
598 return peer.getAcl2Mode();
599 } else {
600 return config.getMode();
601 }
602 }
603
604 public MyInteractiveSessionConfig getConfig() {
605 config.setMode(getAcl2Mode());
606 config.setBaseConfig(Acl2sPlugin.getBaseConfig());
607 config.setAcl2CustomizationOverride(Acl2Prefs.getCustomizationOverride(null, this));
608 config.setSuperHistoryEnabled(peer != null && peer.getLineMode().cancelOnError());
609 config.setSuperHistoryTrackMonitorsOverride(InteractionPrefs.getTrackMonitorsOverride(null, this));
610 config.setSuperHistoryTrackPresentationOverride(InteractionPrefs.getTrackPresentationOverride(null, this));
611 return config;
612 }
613
614 public void setAcl2Mode(SessionMode mode) {
615 if (peer != null) {
616 peer.setAcl2Mode(mode);
617 } else {
618 config.setMode(mode);
619 }
620 }
621
622 void append(String s, String typ) {
623 if (s.length() == 0) return;
624 partitioner.preAppend(typ);
625 newDumpLength = dumpLength + s.length();
626 replace2(dumpLength, 0, s);
627 dumpLength = newDumpLength;
628 }
629
630 protected void doFireDocumentChanged2(DocumentEvent event) {
631 super.doFireDocumentChanged2(event);
632 /*if (event.fOffset > dumpLength &&
633 (event.fText.equals("\r") || event.fText.equals("\n"))) {
634 trySubmitImmediate();
635 }*/
636 }
637
638 /*transient boolean replacingSep = false;
639 public void updateSep() {
640 String immediate = getImmediate();
641 if (immediate.indexOf('\n') >= 0 || immediate.indexOf('\r') >= 0) {
642 if (getChar2(dumpLength) == ' ') {
643 replacingSep = true;
644 replace2(dumpLength, 1, "\n");
645 replacingSep = false;
646 }
647 } else {
648 if (getChar2(dumpLength) != ' ') {
649 replacingSep = true;
650 replace2(dumpLength, 1, " ");
651 replacingSep = false;
652 }
653 }
654 }*/
655
656 static final Sym U_KEYWORD = Sym.createKeyword("U");
657 static final Sym UBT_KEYWORD = Sym.createKeyword("UBT");
658 static final Sym UBTB_KEYWORD = Sym.createKeyword("UBT!");
659 static final Sym UBU_KEYWORD = Sym.createKeyword("UBU");
660 static final Sym UBUB_KEYWORD = Sym.createKeyword("UBU!");
661
662 public boolean trySubmitImmediate(SessionEditor ctx) {
663 String immediate = getImmediate() + "\n";
664 StringParser p = new StringParser(null, immediate); // assign here to fix warning (!)
665 try {
666 switch (session.getStatus()) {
667 case ISessionStatusListener.READY_CMD_SESSION:
668 {
669 p = new StringParser(session.getCurrentEnv().getParseContext(), immediate);
670 ResolvableUserInput preCmd = ResolvableUserInput.parse(p,ID,this);
671 p.skipSpaceAndComments();
672 String rest = immediate.substring(p.getPos());
673
674 // special cases:
675 boolean handledSpecially = false;
676 if (preCmd instanceof UnresolvedKeywordCmd && getPeer() != null) {
677 UnresolvedKeywordCmd preKeyCmd = (UnresolvedKeywordCmd) preCmd;
678 Sym key = preKeyCmd.getKeyword();
679 LispObject[] params = preKeyCmd.getParams();
680 if (key == U_KEYWORD) {
681 if (params.length == 0) {
682 // EVERYTHING CHECKS OUT
683 newImmediateCmd(preCmd.getInputString(),rest);
684 IPeerDocument peer = getPeer();
685 peer.retreatLine(ctx);
686 handledSpecially = true;
687 }
688 } else if (key == UBT_KEYWORD || key == UBTB_KEYWORD ||
689 key == UBU_KEYWORD || key == UBUB_KEYWORD) {
690 if (params.length == 1) {
691 IResultInfo r;
692 if (key == UBT_KEYWORD || key == UBTB_KEYWORD) {
693 r = session.systemCmd2("(acl2s::print-ubt-superlen " + params[0].toString() + ")\n");
694 } else {
695 r = session.systemCmd2("(acl2s::print-ubu-superlen " + params[0].toString() + ")\n");
696 }
697
698 try {
699 String output = r.getOutput();
700 int lstart = output.indexOf("INDEX:");
701 if (lstart < 0) throw new NumberFormatException();
702 int numstart = lstart + "INDEX:".length();
703 int numend = Math.max(output.indexOf('\n', numstart), numstart);
704 output = output.substring(numstart, numend);
705 int superLen = Integer.parseInt(output);
706
707 int modlIdx = done.size() - 1;
708 for (;;) {
709 if (modlIdx < 0) break;
710 DoneElement elt = done.get(modlIdx);
711 if (elt == null) break;
712 IEnvInfo env = elt.getEnv();
713 if (env == null) break;
714 if (env.getSuperDoneSize() <= superLen) {
715 // EVERYTHING CHECKS OUT
716 newImmediateCmd(preCmd.getInputString(),rest);
717 IPeerDocument peer = getPeer();
718 peer.retreatBackThrough(ctx, modlIdx);
719 handledSpecially = true;
720 break;
721 }
722 modlIdx--;
723 }
724 } catch (NumberFormatException e) {
725 // do nothing
726 }
727 }
728 }
729 }
730
731 if (!handledSpecially) {
732 ResolvedInput cmd = preCmd.resolve(session);
733 newImmediateCmd(preCmd.getInputString(),rest);
734 if (getPeer() != null && cmd.couldNeedUndo() && InteractionPrefs.isRelevantCmdPrefWormhole(this)) {
735 cmd = new WormholeWrappedInput(cmd);
736 }
737 session.submitCmdInput(cmd);
738 }
739 }
740 break;
741 case ISessionStatusListener.READY_MISC_SESSION:
742 {
743 //p = new StringParser(null, immediate);
744 p.skipSpaceAndComments();
745 final int start = p.getPos();
746 LispObject.parse(p);
747 final int end = p.getPos();
748 String input = immediate.substring(start,end);
749 newImmediateMisc(start,end);
750 session.submitMiscInput(input);
751 }
752 break;
753 default:
754 // ignore
755 }
756 return true; // just means don't insert the '\n'
757 } catch (ParseException pe) {
758 if (p.peek() == StringParser.EOF) return false; // just needs more input
759 ctx.setHighlightRange(dumpLength+1+p.getPos(),0,true);
760 ctx.errorMessageBox("Parse Error", pe.getMessage() +
761 "\n\nCursor has been positioned at spot of error.");
762 return true;
763 } catch (BadCmdException e) {
764 ctx.setHighlightRange(dumpLength+1,0,true);
765 ctx.errorMessageBox("Bad Command", e.getMessage() +
766 "\n\nCursor has been positioned at violating command.");
767 return true;
768 } catch (SessionDeadException e) {
769 // ignore
770 return true;
771 } catch (SessionException e) {
772 // shouldn't happen
773 Acl2sPlugin.logError("Unexpected session state.", e);
774 return true;
775 }
776 }
777
778 protected void newImmediateCmd(String input, String rest) {
779 cmdPos = cmdHistory.size();
780 cmdHistory.set(cmdPos-1,input);
781 cmdHistory.add("");
782 replaceImmediate(rest);
783 }
784
785 protected void newImmediateMisc(int start, int end) {
786 String immediate = getImmediate();
787 String input = immediate.substring(start,end);
788 miscPos = miscHistory.size();
789 miscHistory.set(miscPos-1,input);
790 String rest = immediate.substring(end).trim();
791 miscHistory.add(rest);
792 replaceImmediate(miscHistory.get(miscPos));
793 }
794
795 /*protected void removeFromImmediate(int n) {
796 replace2(dumpLength,Math.min(n,getLength()-dumpLength),"");
797 }
798
799 protected void stowImmediateCmd() {
800 cmdHistory.set(cmdPos,getImmediate().trim());
801 }
802
803 protected void trimImmediateTail() {
804 int newLen = getLength();
805 while (newLen > 0 && Character.isSpaceChar(getChar2(newLen-1))) {
806 newLen--;
807 }
808 replace2(newLen,getLength()-newLen,"");
809 }*/
810
811
812 public void replaceImmediate(String s) {
813 String sep;
814 if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0) {
815 sep = "\n";
816 } else {
817 sep = " ";
818 }
819 replace2(dumpLength,getLength()-dumpLength,sep + s);
820 }
821
822
823 public void cmdPrevious() {
824 switch (session.getStatus()) {
825 case ISessionStatusListener.READY_CMD_SESSION:
826 if (cmdPos == 0) return;
827 cmdHistory.set(cmdPos,getImmediate());
828 cmdPos--;
829 replaceImmediate(cmdHistory.get(cmdPos));
830 resetUndoStuff();
831 break;
832 case ISessionStatusListener.READY_MISC_SESSION:
833 if (miscPos == 0) return;
834 miscHistory.set(miscPos,getImmediate());
835 miscPos--;
836 replaceImmediate(miscHistory.get(miscPos));
837 resetUndoStuff();
838 break;
839 }
840 }
841
842 public void cmdNext() {
843 switch (session.getStatus()) {
844 case ISessionStatusListener.READY_CMD_SESSION:
845 if (cmdPos == cmdHistory.size()-1) return;
846 cmdHistory.set(cmdPos,getImmediate());
847 cmdPos++;
848 replaceImmediate(cmdHistory.get(cmdPos));
849 resetUndoStuff();
850 break;
851 case ISessionStatusListener.READY_MISC_SESSION:
852 if (miscPos == miscHistory.size()-1) return;
853 miscHistory.set(miscPos,getImmediate());
854 miscPos++;
855 replaceImmediate(miscHistory.get(miscPos));
856 resetUndoStuff();
857 break;
858 }
859 }
860
861 public void cmdLast() {
862 switch (session.getStatus()) {
863 case ISessionStatusListener.READY_CMD_SESSION:
864 if (cmdPos == cmdHistory.size()-1) return;
865 cmdHistory.set(cmdPos,getImmediate());
866 cmdPos = cmdHistory.size() - 1;
867 replaceImmediate(cmdHistory.get(cmdPos));
868 resetUndoStuff();
869 break;
870 case ISessionStatusListener.READY_MISC_SESSION:
871 if (miscPos == miscHistory.size()-1) return;
872 miscHistory.set(miscPos,getImmediate());
873 miscPos = miscHistory.size() - 1;
874 replaceImmediate(miscHistory.get(miscPos));
875 resetUndoStuff();
876 break;
877 }
878 }
879
880 public int getNextInputIdx(int start) {
881 return getAdjacentIdx(start,true,inputIdxs);
882 }
883
884 public int getPrevInputIdx(int start) {
885 return getAdjacentIdx(start,false,inputIdxs);
886 }
887
888 public int getNextCheckpointIdx(int start) {
889 return getAdjacentIdx(start,true,checkpointIdxs);
890 }
891
892 public int getPrevCheckpointIdx(int start) {
893 return getAdjacentIdx(start,false,checkpointIdxs);
894 }
895
896 private int getPseudoIndexIdx(int i, ArrayList<Integer> src) {
897 int sz = src.size();
898 if (i < sz - 1) {
899 return src.get(i).intValue();
900 } else if (i == sz - 1) {
901 return dumpLength + 1;
902 } else {
903 return getLength();
904 }
905 }
906
907 private int getAdjacentIdx(int start, boolean direction, ArrayList<Integer> src) {
908 int max = src.size();
909 if (max == 0) return 0;
910 int inc = 0x10000000;
911 int i = 0;
912 while (inc > 0) { // binary search, undershoot
913 if (i+inc <= max && getPseudoIndexIdx(i+inc,src) < start) {
914 i += inc;
915 }
916 inc >>= 1;
917 }
918 if (direction && i < max) {
919 i++;
920 if (getPseudoIndexIdx(i,src) == start && i < max) {
921 i++;
922 }
923 }
924 return getPseudoIndexIdx(i,src);
925 }
926
927 public int getModelIdxOfOffset(int offset) {
928 for (int i = inputIdxs.size() - 1; i > 0; i--) {
929 if (offset >= inputIdxs.get(i).intValue()) return i;
930 }
931 return 0;
932 }
933
934 public int getOffsetOfModelIdx(int idx) {
935 return inputIdxs.get(idx).intValue();
936 }
937
938 public static final String PROMPT = "__a2s_session_prompt";
939 public static final String CMDTYPE = "__a2s_session_cmdtype";
940 public static final String INPUT = "__a2s_session_input";
941 public static final String OUTPUT = "__a2s_session_output";
942 public static final String OUTPUTERR = "__a2s_session_outputerr";
943
944 public static String[] getContentTypes() {
945 return new String[] { PROMPT, CMDTYPE, INPUT, OUTPUT, OUTPUTERR, Partitioner.DEFAULT };
946 }
947
948 public String[] getLegalContentTypes() {
949 return getContentTypes();
950 }
951
952 // must be static or else tries to serialize the document
953 static class Partitioner extends AbstractDocumentPartitioner implements Serializable {
954 private static final long serialVersionUID = 2L;
955
956 transient String appendType = null;
957 transient SessionDocument doc = null;
958
959 public Partitioner() {
960 super();
961 addRegion(0,1,DEFAULT);
962 }
963
964 public String[] getLegalContentTypes() {
965 return getContentTypes();
966 }
967
968 public void connect(IDocument document) {
969 super.connect(document);
970 doc = (SessionDocument) document;
971 }
972
973 public IRegion documentChanged2(DocumentEvent event) {
974 int offset = event.getOffset();
975 if (appendType != null) {
976 int idx = getLastDumpRegionIdx();
977 int len = event.getText().length();
978 MyTypedRegion r = idx >= 0 ? regions.get(idx) : new MyTypedRegion(0,0,DEFAULT);
979 if (r.getType().equals(appendType)) {
980 //System.err.println("Replacing a " + appendType);
981 replaceRegion(idx,new MyTypedRegion(r.getOffset(),r.getLength()+len,appendType),true);
982 offset = r.getOffset();
983 } else {
984 //System.err.println("Inserting a " + appendType);
985 insertRegion(idx+1,new MyTypedRegion(offset,len,appendType),true);
986 }
987 appendType = null;
988 }
989 MyTypedRegion r = new MyTypedRegion(doc.newDumpLength,doc.getLength()-doc.newDumpLength,DEFAULT);
990 replaceRegion(getImmediateRegionIdx(),r,true);
991
992 return new Region(offset,doc.getLength()-offset);
993 }
994
995 int getLastDumpRegionIdx() {
996 return regions.size() - 2;
997 }
998
999 int getImmediateRegionIdx() {
1000 return regions.size() - 1;
1001 }
1002
1003 void preAppend(String typ) {
1004 if (appendType != null) {
1005 throw new IllegalStateException();
1006 }
1007 appendType = typ;
1008 }
1009
1010 public void changeLastType(String fromTyp, String toTyp) {
1011 int idx = getLastDumpRegionIdx();
1012 if (idx < 0) return;
1013 MyTypedRegion r = regions.get(idx);
1014 if (r.getType().equals(fromTyp)) {
1015 replaceRegion(idx,new MyTypedRegion(r.getOffset(),r.getLength(),toTyp),false);
1016 doc.setDocumentPartitioner(Partitioner.this);
1017 }
1018 }
1019 }
1020
1021
1022
1023 static final class CurElement implements Serializable {
1024 private static final long serialVersionUID = 5L;
1025
1026 transient SessionDocument doc = null;
1027 void connect(SessionDocument d) { doc = d; }
1028
1029 IEnvInfo env;
1030 IInputInfo input;
1031 final StringBuilder output = new StringBuilder();
1032 StringBuilder proofTree = new StringBuilder();
1033 StringBuilder nextProofTree = new StringBuilder();
1034 IStatusInfo status;
1035 ArrayList<Integer> chkptOffsets = new ArrayList<Integer>();
1036 ArrayList<String> chkptNames = new ArrayList<String>();
1037
1038 boolean hideOutput;
1039 int outputPos;
1040 boolean inProofTree;
1041
1042 public void init(IEnvInfo env) {
1043 this.env = env;
1044 input = null;
1045 output.setLength(0);
1046 outputPos = 0;
1047 status = null;
1048 if (env.getPrompt() != null)
1049 doc.append(env.getPrompt(), PROMPT);
1050 doc.inputIdxs.add(Integer.valueOf(doc.dumpLength));
1051 doc.checkpointIdxs.add(Integer.valueOf(doc.dumpLength));
1052 chkptOffsets.clear();
1053 chkptNames.clear();
1054 inProofTree = false;
1055 proofTree.setLength(0);
1056 nextProofTree.setLength(0);
1057 }
1058
1059 public void nextInput(IInputInfo i) {
1060 if (input != null) throw new IllegalStateException();
1061 input = i;
1062 if (i.getInputTypeString() != null)
1063 doc.append(i.getInputTypeString() + " ", CMDTYPE);
1064 if (i.getInputString() != null) {
1065 if (i.getInputString().indexOf('\n') > 0) {
1066 // prefix a newline so that indention looks right
1067 doc.append("\n" + i.getInputString() + "\n", INPUT);
1068 } else {
1069 doc.append(i.getInputString() + "\n", INPUT);
1070 }
1071 }
1072 if (i.getMetaOutput() != null) {
1073 doc.append(i.getMetaOutput() + "\n", OUTPUT);
1074 }
1075 hideOutput = input.hideOutput();
1076
1077 startProofTree();
1078 endProofTree(); // notify listeners of clear output
1079 }
1080
1081 public void appendOutput(String s) {
1082 if (input == null) throw new IllegalStateException();
1083 if (inProofTree) {
1084 nextProofTree.append(s);
1085 } else {
1086 output.append(s);
1087 }
1088 }
1089
1090 //harshrc:: Heres where Peter sets the checkpoint offsets and
1091 //remembers the goal names.
1092 public void layDownCheckpoint(String goalStr) {
1093 if (input == null) throw new IllegalStateException();
1094 chkptOffsets.add(Integer.valueOf(output.length()));
1095 chkptNames.add(goalStr);
1096 flushOutput();
1097 doc.checkpointIdxs.add(Integer.valueOf(doc.dumpLength));
1098 output.append("^^^ Checkpoint " + goalStr + " ^^^\n");
1099 }
1100
1101 public void flushOutput() {
1102 if (!hideOutput && output.length() > outputPos) {
1103 doc.append(output.substring(outputPos), OUTPUT);
1104 outputPos = output.length();
1105 }
1106 }
1107
1108 public void startProofTree() {
1109 inProofTree = true;
1110 nextProofTree.setLength(0);
1111 }
1112
1113 public void endProofTree() {
1114 inProofTree = false;
1115
1116 StringBuilder tmp = proofTree;
1117 tmp.setLength(0); // recycle
1118 proofTree = nextProofTree;
1119 nextProofTree = tmp;
1120
1121 int idx = doc.countCompletedCmds();
1122 for (IProofTreeListener l : doc.listeners) {
1123 l.newProofTree(doc,idx);
1124 }
1125 }
1126
1127
1128 public DoneElement finish(IStatusInfo s) {
1129 flushOutput();
1130 /*if (proofTree.length() > 0) {
1131 doc.append(">>> Final proof tree output:\n", OUTPUT);
1132 doc.append(proofTree.toString(), OUTPUT);
1133 doc.append("<<< (end of proof tree output)\n", OUTPUT);
1134 }*/
1135 if (!s.wasSuccess()) {
1136 doc.partitioner.changeLastType(OUTPUT,OUTPUTERR);
1137 }
1138 status = s;
1139 return new DoneElement(this);
1140 }
1141
1142 public DoneElement forceFinish() {
1143 flushOutput();
1144 return new DoneElement(this);
1145 }
1146
1147 public IEnvInfo getEnv() { return env; }
1148 public IInputInfo getInput() { return input; }
1149 public String getOutput() { return output.toString(); }
1150 public IStatusInfo getStatus() { return status; }
1151 }
1152
1153 static final class DoneElement implements Serializable {
1154 private static final long serialVersionUID = 5L;
1155
1156 final IEnvInfo env;
1157 final IInputInfo input;
1158 final String output;
1159 final IStatusInfo status;
1160 final int[] chkptOffsets;
1161 final String[] chkptNames;
1162 final String finalProofTree;
1163
1164 public DoneElement(CurElement that) {
1165 this.env = that.env;
1166 this.input = that.input;
1167 this.output = that.output.toString();
1168 this.status = that.status;
1169 int sz = that.chkptOffsets.size();
1170 assert sz == that.chkptNames.size();
1171 this.chkptOffsets = new int[sz];
1172 this.chkptNames = new String[sz];
1173 for (int i = 0; i < sz; i++) {
1174 this.chkptOffsets[i] = that.chkptOffsets.get(i).intValue();
1175 this.chkptNames[i] = that.chkptNames.get(i);
1176 }
1177 finalProofTree = that.proofTree.toString();
1178 }
1179
1180 public IEnvInfo getEnv() { return env; }
1181 public IInputInfo getInput() { return input; }
1182 public String getOutput() { return output; }
1183 public IStatusInfo getStatus() { return status; }
1184 public String getFinalProofTree() { return finalProofTree; }
1185 }
1186
1187 public void dispose() {
1188 session.killSession();
1189 session.removeSessionStatusListener(this);
1190 tokens.disconnect();
1191 }
1192
1193 public void interrupt() throws SessionException {
1194 synchronized (session) {
1195 switch (session.getStatus()) {
1196 case READY_MISC_SESSION:
1197 case BUSY_SESSION:
1198 session.interruptSession();
1199 // fall through
1200 case READY_CMD_SESSION:
1201 session.scheduleAbort();
1202 break;
1203 }
1204 }
1205 }
1206
1207
1208 public void reparse() {
1209 tokens.reparse();
1210 }
1211
1212 public void cleanCmdHist() {
1213 cmdHistory.clear();
1214 cmdHistory.add("");
1215 cmdPos = 0;
1216 miscHistory.clear();
1217 miscHistory.add("");
1218 miscPos = 0;
1219 }
1220
1221
1222 // PROOF TREE LISTENERS
1223
1224 protected ArrayList<IProofTreeListener> listeners = new ArrayList<IProofTreeListener>();
1225
1226 public void addProofTreeListener(IProofTreeListener l) {
1227 listeners.add(l);
1228 }
1229
1230 public void removeProofTreeListener(IProofTreeListener l) {
1231 listeners.remove(l);
1232 }
1233
1234 }