visualproof 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +99 -2
- package/dist/assets/fonts/JuliaMono-Regular.ttf +0 -0
- package/dist/assets/fonts/JuliaMono-RegularItalic.ttf +0 -0
- package/dist/assets/fonts/JuliaMono-SemiBold.ttf +0 -0
- package/dist/assets/fonts/LICENSE-JuliaMono.txt +93 -0
- package/dist/assets/latex/visualproof.sty +308 -0
- package/dist/assets/webfonts/LICENSE-Jost.txt +93 -0
- package/dist/assets/webfonts/LICENSE-SourceSans3.txt +93 -0
- package/dist/assets/webfonts/LICENSE-SourceSerif4.txt +93 -0
- package/dist/assets/webfonts/jost-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/jost-latin-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-greek-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-greek-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-ext-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-greek-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-greek-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-ext-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-wght-normal.woff2 +0 -0
- package/dist/extractor/Extract.lean +1180 -0
- package/dist/extractor/Usage.lean +900 -0
- package/dist/mcp/visualproof-mcp.mjs +476 -0
- package/dist/server/access.js +95 -0
- package/dist/server/agent.js +3270 -0
- package/dist/server/agentdocs.js +35 -0
- package/dist/server/agentlibrary.js +202 -0
- package/dist/server/agentnotes.js +701 -0
- package/dist/server/agentviews.js +703 -0
- package/dist/server/askfollow.js +286 -0
- package/dist/server/boardspots.js +159 -0
- package/dist/server/dirs.js +175 -0
- package/dist/server/doctor.js +186 -0
- package/dist/server/events.js +198 -0
- package/dist/server/export.js +420 -0
- package/dist/server/extract.js +204 -0
- package/dist/server/fetchurl.js +321 -0
- package/dist/server/figures.js +158 -0
- package/dist/server/history.js +780 -0
- package/dist/server/historyapi.js +304 -0
- package/dist/server/hover.js +595 -0
- package/dist/server/identity.js +114 -0
- package/dist/server/invites.js +241 -0
- package/dist/server/layoutthread.js +51 -0
- package/dist/server/library.js +600 -0
- package/dist/server/libraryroute.js +211 -0
- package/dist/server/live.js +1101 -0
- package/dist/server/lostfound.js +199 -0
- package/dist/server/main.js +1406 -0
- package/dist/server/mcptools.js +496 -0
- package/dist/server/pastdoc.js +73 -0
- package/dist/server/pipeline.js +159 -0
- package/dist/server/poppler.js +251 -0
- package/dist/server/presence.js +252 -0
- package/dist/server/project.js +222 -0
- package/dist/server/prompt.js +53 -0
- package/dist/server/readonly.js +152 -0
- package/dist/server/readonlygate.js +123 -0
- package/dist/server/renames.js +268 -0
- package/dist/server/review.js +334 -0
- package/dist/server/reviewapi.js +188 -0
- package/dist/server/snapshot.js +50 -0
- package/dist/server/sourcestore.js +473 -0
- package/dist/server/status.js +360 -0
- package/dist/server/talk.js +476 -0
- package/dist/server/tokens.js +221 -0
- package/dist/server/usage.js +501 -0
- package/dist/server/versions.js +82 -0
- package/dist/server/view.js +164 -0
- package/dist/server/views.js +1167 -0
- package/dist/shared/askfollow.js +46 -0
- package/dist/shared/board.js +332 -0
- package/dist/shared/build.js +2 -0
- package/dist/shared/collab.js +241 -0
- package/dist/shared/comment.js +285 -0
- package/dist/shared/context.js +157 -0
- package/dist/shared/doc/authors.js +98 -0
- package/dist/shared/doc/build.js +358 -0
- package/dist/shared/doc/latex.js +455 -0
- package/dist/shared/doc/markdown.js +159 -0
- package/dist/shared/doc/model.js +37 -0
- package/dist/shared/doc/order.js +124 -0
- package/dist/shared/doc/outline.js +45 -0
- package/dist/shared/doc/proof.js +272 -0
- package/dist/shared/doc/sections.js +93 -0
- package/dist/shared/doc/settings.js +75 -0
- package/dist/shared/edgecodec.js +102 -0
- package/dist/shared/editor.js +64 -0
- package/dist/shared/excerpt.js +87 -0
- package/dist/shared/graph.js +16 -0
- package/dist/shared/items.js +92 -0
- package/dist/shared/keys.js +203 -0
- package/dist/shared/layout.js +926 -0
- package/dist/shared/lexer.js +130 -0
- package/dist/shared/library.js +711 -0
- package/dist/shared/lostfound.js +150 -0
- package/dist/shared/moves.js +244 -0
- package/dist/shared/notecard.js +295 -0
- package/dist/shared/noteplace.js +505 -0
- package/dist/shared/palette.js +46 -0
- package/dist/shared/pastgraph.js +103 -0
- package/dist/shared/places.js +80 -0
- package/dist/shared/projectnotes.js +244 -0
- package/dist/shared/query.js +818 -0
- package/dist/shared/review.js +642 -0
- package/dist/shared/reviewqueue.js +333 -0
- package/dist/shared/ring.js +366 -0
- package/dist/shared/scope.js +255 -0
- package/dist/shared/scopeedit.js +81 -0
- package/dist/shared/search.js +191 -0
- package/dist/shared/separate.js +178 -0
- package/dist/shared/sharesnap.js +281 -0
- package/dist/shared/sticky.js +501 -0
- package/dist/shared/timeline.js +73 -0
- package/dist/shared/titles.js +300 -0
- package/dist/shared/viewgraph.js +157 -0
- package/dist/shared/views.js +859 -0
- package/dist/web/bundle/app.js +52671 -0
- package/dist/web/bundle/edges.js +407 -0
- package/dist/web/bundle/layout.js +1010 -0
- package/dist/web/bundle/pdfworker.js +48322 -0
- package/dist/web/index.html +257 -0
- package/dist/web/src/motion.js +430 -0
- package/dist/web/src/past.js +224 -0
- package/dist/web/src/scene.js +804 -0
- package/dist/web/style.css +2548 -0
- package/docs/agent-api/README.md +91 -0
- package/docs/agent-api/advice.md +108 -0
- package/docs/agent-api/export.md +120 -0
- package/docs/agent-api/following.md +140 -0
- package/docs/agent-api/history.md +142 -0
- package/docs/agent-api/library.md +65 -0
- package/docs/agent-api/mcp.md +104 -0
- package/docs/agent-api/notes.md +93 -0
- package/docs/agent-api/reading.md +166 -0
- package/docs/agent-api/requests.md +94 -0
- package/docs/agent-api/talking.md +100 -0
- package/docs/agent-api/tcb.md +135 -0
- package/docs/agent-api/views.md +125 -0
- package/docs/agent-api/words.md +56 -0
- package/package.json +39 -4
- package/test/toolchains.json +5 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
// The order in which to review a target's TCB and why a declaration is in the TCB at all
|
|
2
|
+
// (ReviewSpec, "Reviewing a target"): pure functions of the graph and the review. The page's review
|
|
3
|
+
// (web/src/reviewqueue.ts: the strip, the target's review list), the agent API (server/agent.ts) and
|
|
4
|
+
// the server's checks of key declarations (server/reviewapi.ts) walk a TCB the same way.
|
|
5
|
+
//
|
|
6
|
+
// Where the review works is a view's focus (ViewSpec decision 28; shared/views.ts, viewFocus), not
|
|
7
|
+
// what its scope says; whatever the board holds, the review counts the focus's whole review set.
|
|
8
|
+
//
|
|
9
|
+
// What a target's review holds (decided 2026-10-08) is the scope `reviewScope` (shared/query.ts)
|
|
10
|
+
// evaluated on the graph — the TCB without what is trusted, an untrusted outside declaration
|
|
11
|
+
// included, and every non-standard axiom the target rests on through statements, bodies or proofs,
|
|
12
|
+
// which no prefix trusts. The queue and its progress count exactly that set, so that a board of that
|
|
13
|
+
// scope and the numbers beside it never disagree. An axiom the graph has no declaration for (one only
|
|
14
|
+
// the axiom sets name, used inside something outside the project) cannot be on a board: it is
|
|
15
|
+
// counted beside the queue, and approved from the target's panel.
|
|
16
|
+
import { SITE_BODY, SITE_STMT } from "./graph.js";
|
|
17
|
+
import { current, fresh, STANDARD_AXIOMS, statusOf, trusted } from "./review.js";
|
|
18
|
+
import { ALL_SITES } from "./viewgraph.js";
|
|
19
|
+
import { evaluate, reviewScope } from "./query.js";
|
|
20
|
+
/** The references a TCB follows: in statements and bodies, never inside a proof. */
|
|
21
|
+
export const TCB_SITES = SITE_STMT | SITE_BODY;
|
|
22
|
+
/** In how many of the targets' TCBs each declaration is. */
|
|
23
|
+
export function inTargets(g, targets) {
|
|
24
|
+
const out = new Uint16Array(g.n);
|
|
25
|
+
for (const t of targets) {
|
|
26
|
+
const tcb = g.reach([t], TCB_SITES, "out");
|
|
27
|
+
for (let i = 0; i < g.n; i++)
|
|
28
|
+
out[i] += tcb[i];
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
/** Whether declaration `i` is an axiom beyond Lean's three standard ones: it needs review whatever
|
|
33
|
+
* is trusted (ReviewSpec decision 3). */
|
|
34
|
+
export function nonStandardAxiom(g, i) {
|
|
35
|
+
return g.nodes[i].kind === "axiom" && !STANDARD_AXIOMS.includes(g.nodes[i].name);
|
|
36
|
+
}
|
|
37
|
+
/** Whether declaration `i` needs review where it is in a target's TCB: no prefix trusts it, or it
|
|
38
|
+
* is a non-standard axiom. */
|
|
39
|
+
export function needsReview(g, d, i) {
|
|
40
|
+
return nonStandardAxiom(g, i) || !trusted(d, g.nodes[i].name, g.nodes[i].module, g.isExt(i));
|
|
41
|
+
}
|
|
42
|
+
/** What `root`'s review holds, its review set (`reviewScope`), in the graph's numbering. */
|
|
43
|
+
export function reviewSet(g, d, root) {
|
|
44
|
+
return evaluate(reviewScope(g.nodes[root].name), { g, review: d });
|
|
45
|
+
}
|
|
46
|
+
const VIA = 8;
|
|
47
|
+
/** The non-standard axioms `root` rests on, through statements, bodies or proofs: those the axiom
|
|
48
|
+
* sets of what it reaches name (the extractor's, through everything), and those it reaches as
|
|
49
|
+
* declarations. `set` is its review's set (reviewSet). */
|
|
50
|
+
export function axiomsReached(g, root, set) {
|
|
51
|
+
const meta = g.meta;
|
|
52
|
+
const reach = g.reach([root], ALL_SITES, "out");
|
|
53
|
+
const names = new Set();
|
|
54
|
+
for (let i = 0; i < g.n; i++) {
|
|
55
|
+
if (!reach[i])
|
|
56
|
+
continue;
|
|
57
|
+
if (nonStandardAxiom(g, i))
|
|
58
|
+
names.add(g.nodes[i].name);
|
|
59
|
+
for (const k of meta.axiomSets[g.nodes[i].ax] ?? [])
|
|
60
|
+
if (!STANDARD_AXIOMS.includes(meta.axioms[k]))
|
|
61
|
+
names.add(meta.axioms[k]);
|
|
62
|
+
}
|
|
63
|
+
const out = [];
|
|
64
|
+
for (const name of [...names].sort()) {
|
|
65
|
+
const j = g.byName.get(name);
|
|
66
|
+
const node = j !== undefined && set[j] ? j : null;
|
|
67
|
+
const via = [];
|
|
68
|
+
if (node !== null) {
|
|
69
|
+
for (let e = g.inStart[node]; e < g.inStart[node + 1]; e++)
|
|
70
|
+
if (reach[g.inSrc[e]] && g.inSrc[e] !== node && !via.includes(g.inSrc[e]))
|
|
71
|
+
via.push(g.inSrc[e]);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const k = meta.axioms.indexOf(name);
|
|
75
|
+
const rests = (i) => k >= 0 && (meta.axiomSets[g.nodes[i].ax] ?? []).includes(k);
|
|
76
|
+
for (let i = 0; i < g.n; i++) {
|
|
77
|
+
if (!reach[i] || !rests(i))
|
|
78
|
+
continue;
|
|
79
|
+
let deeper = false;
|
|
80
|
+
for (let e = g.outStart[i]; e < g.outStart[i + 1] && !deeper; e++)
|
|
81
|
+
deeper = g.outDst[e] !== i && rests(g.outDst[e]);
|
|
82
|
+
if (!deeper)
|
|
83
|
+
via.push(i);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// the project's own first: that is where someone can do something about it
|
|
87
|
+
via.sort((a, b) => Number(g.isExt(a)) - Number(g.isExt(b)) || (g.nodes[a].name < g.nodes[b].name ? -1 : 1));
|
|
88
|
+
out.push({ name, node, via: via.slice(0, VIA) });
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
/** `root`'s review queue. `shared`: in how many targets' TCBs each declaration is (inTargets). */
|
|
93
|
+
export function reviewQueue(g, d, root, shared) {
|
|
94
|
+
const set = reviewSet(g, d, root);
|
|
95
|
+
const order = reviewOrder(g, set, shared);
|
|
96
|
+
const ax = order.filter((i) => g.nodes[i].kind === "axiom");
|
|
97
|
+
return { order: [...ax, ...order.filter((i) => g.nodes[i].kind !== "axiom")], axioms: axiomsReached(g, root, set) };
|
|
98
|
+
}
|
|
99
|
+
/** The axioms of a queue the graph has no declaration for on the board. */
|
|
100
|
+
export function offBoard(q) {
|
|
101
|
+
return q.axioms.filter((a) => a.node === null);
|
|
102
|
+
}
|
|
103
|
+
/** How far a target's review has come: every member of its queue, the axioms beside it included. */
|
|
104
|
+
export function queueProgress(g, d, q) {
|
|
105
|
+
const p = { total: 0, approved: 0, commented: 0, stale: 0 };
|
|
106
|
+
const count = (name, hash) => {
|
|
107
|
+
p.total++;
|
|
108
|
+
const s = statusOf(d, name, hash);
|
|
109
|
+
if (s === "approved")
|
|
110
|
+
p.approved++;
|
|
111
|
+
else if (s === "commented")
|
|
112
|
+
p.commented++;
|
|
113
|
+
else if (s === "stale")
|
|
114
|
+
p.stale++;
|
|
115
|
+
};
|
|
116
|
+
for (const i of q.order)
|
|
117
|
+
count(g.nodes[i].name, g.nodes[i].hash);
|
|
118
|
+
for (const a of offBoard(q))
|
|
119
|
+
count(a.name, undefined);
|
|
120
|
+
return p;
|
|
121
|
+
}
|
|
122
|
+
/** How many members `root`'s review counts under the review `d` (what trusting a prefix would
|
|
123
|
+
* change, web/src/trust.ts): its review set, and the axioms beside it. */
|
|
124
|
+
export function reviewCount(g, d, root) {
|
|
125
|
+
const set = reviewSet(g, d, root);
|
|
126
|
+
let n = 0;
|
|
127
|
+
for (let i = 0; i < g.n; i++)
|
|
128
|
+
n += set[i];
|
|
129
|
+
return n + axiomsReached(g, root, set).filter((a) => a.node === null).length;
|
|
130
|
+
}
|
|
131
|
+
/** Whether a reader is done with a member of a review: they gave an opinion on its present
|
|
132
|
+
* version — and, for a non-standard axiom, it is approved, so that "All reviewed" is never said
|
|
133
|
+
* while one is not. */
|
|
134
|
+
export function settled(d, reader, name, hash, axiom) {
|
|
135
|
+
return reviewedBy(d, reader, name, hash) && (!axiom || statusOf(d, name, hash) === "approved");
|
|
136
|
+
}
|
|
137
|
+
/** The declarations of `members` (a target's review, reviewSet) in the order to review them:
|
|
138
|
+
* bottom-up, what a declaration uses before it, since reviewing one means "it says what it
|
|
139
|
+
* should, given that what it uses means what it says" (ReviewSpec decision 2). Declarations that
|
|
140
|
+
* use each other are one step, together. Where the order leaves a choice, what more targets rest
|
|
141
|
+
* on comes first (`shared`, per declaration: one review of a common foundation advances every
|
|
142
|
+
* target on it), then the name. */
|
|
143
|
+
export function reviewOrder(g, set, shared) {
|
|
144
|
+
const members = [];
|
|
145
|
+
for (let i = 0; i < g.n; i++)
|
|
146
|
+
if (set[i])
|
|
147
|
+
members.push(i);
|
|
148
|
+
return dependencyOrder(g, members, (x, y) => (shared[x] !== shared[y] ? shared[x] > shared[y] : g.nodes[x].name < g.nodes[y].name));
|
|
149
|
+
}
|
|
150
|
+
/** Declarations `members` of `g` in dependency order, over statement and body references among
|
|
151
|
+
* them: what a declaration uses before it, declarations that use each other together, one step;
|
|
152
|
+
* where the order leaves a choice, `before` decides (by default, the name). The review queue's
|
|
153
|
+
* order (reviewOrder). */
|
|
154
|
+
export function dependencyOrder(g, members, before = (x, y) => g.nodes[x].name < g.nodes[y].name) {
|
|
155
|
+
const local = new Map();
|
|
156
|
+
members.forEach((v, k) => local.set(v, k));
|
|
157
|
+
// what each member uses among the members; nothing outside the project uses the project, so no
|
|
158
|
+
// path between two members of a review leaves them
|
|
159
|
+
const uses = members.map(() => []);
|
|
160
|
+
members.forEach((u, a) => {
|
|
161
|
+
for (let e = g.outStart[u]; e < g.outStart[u + 1]; e++) {
|
|
162
|
+
const b = g.outSite[e] & TCB_SITES ? local.get(g.outDst[e]) : undefined;
|
|
163
|
+
if (b !== undefined && b !== a)
|
|
164
|
+
uses[a].push(b);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
return stepOrder(uses, (a, b) => before(members[a], members[b])).map((a) => members[a]);
|
|
168
|
+
}
|
|
169
|
+
/** Items in dependency order, given what each uses (`uses`, by index): what an item uses before it,
|
|
170
|
+
* items that use each other as one step, together; where the order leaves a choice, the step
|
|
171
|
+
* whose first item comes `before` the other's first goes first, and within a step `before` orders
|
|
172
|
+
* the items. The indices, in order. */
|
|
173
|
+
export function stepOrder(uses, before) {
|
|
174
|
+
const m = uses.length;
|
|
175
|
+
const comp = components(uses);
|
|
176
|
+
const nc = comp.reduce((x, c) => Math.max(x, c + 1), 0);
|
|
177
|
+
// each step's items in the order of choice; a step is chosen by its first
|
|
178
|
+
const steps = Array.from({ length: nc }, () => []);
|
|
179
|
+
for (let a = 0; a < m; a++)
|
|
180
|
+
steps[comp[a]].push(a);
|
|
181
|
+
for (const s of steps)
|
|
182
|
+
s.sort((a, b) => (before(a, b) ? -1 : before(b, a) ? 1 : 0));
|
|
183
|
+
// a step is ready once every step it uses is done
|
|
184
|
+
const waiting = new Int32Array(nc);
|
|
185
|
+
const usedBy = Array.from({ length: nc }, () => []);
|
|
186
|
+
const seen = new Set();
|
|
187
|
+
for (let a = 0; a < m; a++) {
|
|
188
|
+
for (const b of uses[a]) {
|
|
189
|
+
const c = comp[a], d = comp[b];
|
|
190
|
+
if (c === d || seen.has(c * nc + d))
|
|
191
|
+
continue;
|
|
192
|
+
seen.add(c * nc + d);
|
|
193
|
+
waiting[c]++;
|
|
194
|
+
usedBy[d].push(c);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const ready = new Heap((c, d) => before(steps[c][0], steps[d][0]));
|
|
198
|
+
for (let c = 0; c < nc; c++)
|
|
199
|
+
if (!waiting[c])
|
|
200
|
+
ready.push(c);
|
|
201
|
+
const out = [];
|
|
202
|
+
while (ready.size) {
|
|
203
|
+
const c = ready.pop();
|
|
204
|
+
for (const a of steps[c])
|
|
205
|
+
out.push(a);
|
|
206
|
+
for (const d of usedBy[c])
|
|
207
|
+
if (--waiting[d] === 0)
|
|
208
|
+
ready.push(d);
|
|
209
|
+
}
|
|
210
|
+
return out;
|
|
211
|
+
}
|
|
212
|
+
/** The strongly connected components of a graph given by its successor lists (Tarjan's, without
|
|
213
|
+
* recursion: a TCB can be deep): each node's component number. */
|
|
214
|
+
function components(succ) {
|
|
215
|
+
const n = succ.length;
|
|
216
|
+
const index = new Int32Array(n).fill(-1);
|
|
217
|
+
const low = new Int32Array(n);
|
|
218
|
+
const comp = new Int32Array(n).fill(-1);
|
|
219
|
+
const onStack = new Uint8Array(n);
|
|
220
|
+
const stack = [];
|
|
221
|
+
let next = 0, nc = 0;
|
|
222
|
+
const enter = (v) => {
|
|
223
|
+
index[v] = low[v] = next++;
|
|
224
|
+
stack.push(v);
|
|
225
|
+
onStack[v] = 1;
|
|
226
|
+
};
|
|
227
|
+
for (let s = 0; s < n; s++) {
|
|
228
|
+
if (index[s] >= 0)
|
|
229
|
+
continue;
|
|
230
|
+
enter(s);
|
|
231
|
+
// the path being explored: a node and how many of its successors it has looked at
|
|
232
|
+
const path = [[s, 0]];
|
|
233
|
+
while (path.length) {
|
|
234
|
+
const top = path[path.length - 1];
|
|
235
|
+
const v = top[0];
|
|
236
|
+
if (top[1] < succ[v].length) {
|
|
237
|
+
const w = succ[v][top[1]++];
|
|
238
|
+
if (index[w] < 0) {
|
|
239
|
+
enter(w);
|
|
240
|
+
path.push([w, 0]);
|
|
241
|
+
}
|
|
242
|
+
else if (onStack[w])
|
|
243
|
+
low[v] = Math.min(low[v], index[w]);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
path.pop();
|
|
247
|
+
if (path.length) {
|
|
248
|
+
const u = path[path.length - 1][0];
|
|
249
|
+
low[u] = Math.min(low[u], low[v]);
|
|
250
|
+
}
|
|
251
|
+
if (low[v] === index[v]) {
|
|
252
|
+
let w;
|
|
253
|
+
do {
|
|
254
|
+
w = stack.pop();
|
|
255
|
+
onStack[w] = 0;
|
|
256
|
+
comp[w] = nc;
|
|
257
|
+
} while (w !== v);
|
|
258
|
+
nc++;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return comp;
|
|
263
|
+
}
|
|
264
|
+
/** A binary heap: `pop` gives the item that comes `before` all others. */
|
|
265
|
+
class Heap {
|
|
266
|
+
xs = [];
|
|
267
|
+
before;
|
|
268
|
+
constructor(before) {
|
|
269
|
+
this.before = before;
|
|
270
|
+
}
|
|
271
|
+
get size() {
|
|
272
|
+
return this.xs.length;
|
|
273
|
+
}
|
|
274
|
+
push(x) {
|
|
275
|
+
const xs = this.xs;
|
|
276
|
+
xs.push(x);
|
|
277
|
+
for (let k = xs.length - 1; k > 0;) {
|
|
278
|
+
const p = (k - 1) >> 1;
|
|
279
|
+
if (!this.before(xs[k], xs[p]))
|
|
280
|
+
break;
|
|
281
|
+
[xs[k], xs[p]] = [xs[p], xs[k]];
|
|
282
|
+
k = p;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
pop() {
|
|
286
|
+
const xs = this.xs;
|
|
287
|
+
const top = xs[0];
|
|
288
|
+
const last = xs.pop();
|
|
289
|
+
if (xs.length) {
|
|
290
|
+
xs[0] = last;
|
|
291
|
+
for (let k = 0;;) {
|
|
292
|
+
const l = 2 * k + 1, r = l + 1;
|
|
293
|
+
let best = k;
|
|
294
|
+
if (l < xs.length && this.before(xs[l], xs[best]))
|
|
295
|
+
best = l;
|
|
296
|
+
if (r < xs.length && this.before(xs[r], xs[best]))
|
|
297
|
+
best = r;
|
|
298
|
+
if (best === k)
|
|
299
|
+
break;
|
|
300
|
+
[xs[k], xs[best]] = [xs[best], xs[k]];
|
|
301
|
+
k = best;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return top;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/** The shortest chain of statement and body references from `from` to `to`, both included: why
|
|
308
|
+
* `to` is in `from`'s TCB. Null when it is not. */
|
|
309
|
+
export function whyChain(g, from, to) {
|
|
310
|
+
const parent = new Int32Array(g.n).fill(-1);
|
|
311
|
+
parent[from] = from;
|
|
312
|
+
const queue = [from];
|
|
313
|
+
for (let k = 0; k < queue.length && parent[to] < 0; k++) {
|
|
314
|
+
const u = queue[k];
|
|
315
|
+
for (let e = g.outStart[u]; e < g.outStart[u + 1]; e++) {
|
|
316
|
+
const v = g.outDst[e];
|
|
317
|
+
if (!(g.outSite[e] & TCB_SITES) || parent[v] >= 0)
|
|
318
|
+
continue;
|
|
319
|
+
parent[v] = u;
|
|
320
|
+
queue.push(v);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (parent[to] < 0)
|
|
324
|
+
return null;
|
|
325
|
+
const path = [to];
|
|
326
|
+
while (path[path.length - 1] !== from)
|
|
327
|
+
path.push(parent[path[path.length - 1]]);
|
|
328
|
+
return path.reverse();
|
|
329
|
+
}
|
|
330
|
+
/** Whether `reader` has given an opinion on the present version of a declaration. */
|
|
331
|
+
export function reviewedBy(d, reader, name, hash) {
|
|
332
|
+
return !!reader && current(d, name).some((o) => o.by === reader && fresh(o, hash));
|
|
333
|
+
}
|