1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
use ui;
use core:io;
dialog Dialog {
layout Grid {
expandCol: 0;
Label status("Looking for errors...") { colspan: 2; }
nextLine;
ui:Progress progress() { colspan: 2; }
nextLine;
Label message("") { colspan: 2; }
FillBox(300, 10) { row: 2; col: 0; }
nextLine;
Button ok("Cancel") { col: 1; }
}
init(Url[] files, Checks checks) {
init("Looking for concurrency errors...") {
files = files;
checks = checks;
}
defaultChoice = ok;
progress.wait;
spawn check();
}
// Cancel our progress?
private Bool cancel;
// Are we done?
private Bool done;
// Checks to perform.
private Checks checks;
// Result, if any.
Result? result;
// Update status. Returns 'false' if we shall abort search.
private Bool update(Nat states, Nat edges, Nat unexplored) {
message.text = "Explored ${states} states and ${edges} transitions...";
return !cancel;
}
// Window closed. Abort any running task.
void windowDestroyed() {
cancel = true;
}
// Called when we are done.
void onDestroy(Int code) : override {
cancel = true;
}
// Set us into an error state.
void error(Str message) {
progress.progress = 1.0;
status.text = "Search failed.";
ok.text = "Close";
this.message.text = "An internal error occurred: " + message;
size = minSize();
}
// Set us in a "done" state.
void done(Result? result) {
this.result = result;
progress.progress = 1.0;
status.text = "Done!";
if (result) {
message.text = "Found an error (${result.error.type}):\n${result.error.message}\n\nClick \"Show\" below to see the issue.";
ok.text = "Show";
} else {
message.text = "No errors found, at least not with this main program.";
ok.text = "Close";
}
size = minSize();
}
private Url[] files;
private void check() {
try {
var result = check(files, UiProgress(this), checks);
done(result);
} catch (progvis:program:ExitError e) {
// Early exit.
} catch (Exception e) {
error(e.message);
}
}
// Progress callbacks.
class UiProgress extends Progress {
init(Dialog owner) {
init { owner = owner; }
}
Dialog owner;
Moment lastCheck;
void progress(Nat depth, Nat states, Nat edges, Nat unexplored) : override {
Moment now;
if (now - lastCheck > 1 s) {
lastCheck = now;
if (!owner.update(states, edges, unexplored))
throw progvis:program:ExitError();
}
}
}
}
// Show a dialog for finding errors, and return the result.
Result? findErrorsUi(Frame parent, Url[] files, Checks checks) on Ui {
Dialog d(files, checks);
if (d.show(parent) > 0) {
return d.result;
}
null;
}
Result? findErrorsUi(Frame parent, Url[] files) on Ui {
findErrorsUi(parent, files, Checks());
}
|