drakongen 1.4.6 → 1.7.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/browser/drakongen.js +1362 -722
- package/browsertest.html +9 -1
- package/buildexamples.js +51 -4
- package/exampleproject/foo.txt +2 -0
- package/examples/20. /320/227/320/276/320/273/320/276/321/202/320/276/320/271 - /320/273/320/265/320/262/321/213/320/271 final.drakon" +66 -0
- package/examples/21. /320/227/320/276/320/273/320/276/321/202/320/276/320/271 - /320/277/321/200/320/260/320/262/321/213/320/271 final.drakon" +66 -0
- package/examples/Complex arrow-parallel.drakon +116 -0
- package/examples/Complex arrow-parallel.txt +40 -0
- package/examples/Complex arrow.txt +1 -0
- package/examples/How to tune PID on a quadcopter.txt +1 -0
- package/examples/NestedArrowLoop.drakon +38 -0
- package/examples/NestedArrowLoop.txt +20 -0
- package/examples/all icons.drakon +227 -0
- package/examples/all icons.txt +68 -0
- package/examples/ar01-action.drakon +31 -0
- package/examples/ar01-action.txt +9 -0
- package/examples/ar10-parallel.drakon +70 -0
- package/examples/ar10-parallel.txt +20 -0
- package/examples/badShortCircuit.drakon +34 -0
- package/examples/badShortCircuit.txt +7 -0
- package/examples/getToken.txt +2 -0
- package/examples/monitorPaymentStatus.drakon +56 -0
- package/examples/monitorPaymentStatus.txt +25 -0
- package/examples/no-loop/00.Empty.txt +6 -0
- package/examples/no-loop/01. /320/221/320/265/320/273/321/213/320/271.txt" +5 -0
- package/examples/no-loop/02. /320/247/321/221/321/200/320/275/321/213/320/271.txt" +8 -0
- package/examples/no-loop/03. /320/241/320/265/321/200/321/213/320/271.txt" +7 -0
- package/examples/no-loop/04. /320/221/321/203/321/200/321/213/320/271.txt" +7 -0
- package/examples/no-loop/05. /320/226/321/221/320/273/321/202/321/213/320/271.txt" +7 -0
- package/examples/no-loop/06. /320/221/320/260/320/263/321/200/320/276/320/262/321/213/320/271.txt" +9 -0
- package/examples/no-loop/07. /320/244/320/270/320/276/320/273/320/265/321/202/320/276/320/262/321/213/320/271.txt" +12 -0
- package/examples/no-loop/08. /320/221/320/270/321/200/321/216/320/267/320/276/320/262/321/213/320/271.txt" +7 -0
- package/examples/no-loop/09. /320/236/321/200/320/260/320/275/320/266/320/265/320/262/321/213/320/271.txt" +9 -0
- package/examples/no-loop/10. /320/240/320/276/320/267/320/276/320/262/321/213/320/271.txt" +13 -0
- package/examples/no-loop/11. /320/227/320/260/321/211/320/270/321/202/320/275/321/213/320/271.txt" +9 -0
- package/examples/no-loop/12. /320/221/320/276/320/273/320/276/321/202/320/275/321/213/320/271.txt" +9 -0
- package/examples/no-loop/13. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +15 -0
- package/examples/no-loop/14. /320/227/320/276/320/273/320/276/321/202/320/276/320/271.txt" +17 -0
- package/examples/no-loop/15. /320/241/320/270/320/275/320/270/320/271.txt" +20 -0
- package/examples/no-loop/16. /320/223/320/276/320/273/321/203/320/261/320/276/320/271.txt" +11 -0
- package/examples/no-loop/17. /320/241/320/260/320/273/320/260/321/202/320/276/320/262/321/213/320/271.txt" +10 -0
- package/examples/no-loop/18. /320/241/321/202/320/260/320/273/321/214/320/275/320/276/320/271.txt" +15 -0
- package/examples/no-loop/19. Lilla.txt +11 -0
- package/examples/no-loop/20. /320/227/320/276/320/273/320/276/321/202/320/276/320/271 - /320/273/320/265/320/262/321/213/320/271 final.txt" +16 -0
- package/examples/no-loop/21. /320/227/320/276/320/273/320/276/321/202/320/276/320/271 - /320/277/321/200/320/260/320/262/321/213/320/271 final.txt" +17 -0
- package/examples/no-loop/Adaptive design.txt +31 -0
- package/examples/no-loop/And test.txt +9 -0
- package/examples/no-loop/Comments.txt +19 -0
- package/examples/no-loop/Logical_And.txt +9 -0
- package/examples/no-loop/Logical_And_Inv.txt +9 -0
- package/examples/no-loop/Logical_And_Inv_x2.txt +15 -0
- package/examples/no-loop/Logical_Or.txt +9 -0
- package/examples/no-loop/Logical_Or_Inv.txt +9 -0
- package/examples/no-loop/Mind one.txt +18 -0
- package/examples/no-loop/Or test.txt +9 -0
- package/examples/no-loop/Silhouette test 1.txt +31 -0
- package/examples/no-loop/badShortCircuit.txt +7 -0
- package/examples/no-loop/getToken.txt +34 -0
- package/examples/no-loop/monitorPaymentStatus.txt +25 -0
- package/examples/no-loop/sil2.txt +29 -0
- package/examples/no-loop/tmp.txt +35 -0
- package/examples/no-loop//320/241/320/265/320/274/320/260/320/275/321/202/320/270/321/207/320/265/321/201/320/272/320/276/320/265 /321/217/320/264/321/200/320/276.txt" +36 -0
- package/examples/parallel-3.drakon +49 -0
- package/examples/parallel-3.txt +12 -0
- package/examples/parallel-arrow-loop.drakon +44 -0
- package/examples/parallel-arrow-loop.txt +12 -0
- package/examples/parallel-empty-nested.drakon +40 -0
- package/examples/parallel-empty-nested.txt +11 -0
- package/examples/parallel-empty.drakon +27 -0
- package/examples/parallel-empty.txt +8 -0
- package/examples/parallel-nested.drakon +67 -0
- package/examples/parallel-nested.txt +16 -0
- package/examples/sil2.txt +1 -0
- package/examples/tmp.txt +2 -0
- package/examples//320/241/320/265/320/274/320/260/320/275/321/202/320/270/321/207/320/265/321/201/320/272/320/276/320/265 /321/217/320/264/321/200/320/276.free" +130 -0
- package/examples//320/241/320/265/320/274/320/260/320/275/321/202/320/270/321/207/320/265/321/201/320/272/320/276/320/265 /321/217/320/264/321/200/320/276.txt" +36 -0
- package/package.json +1 -1
- package/prompts/noloop/decrement_if_count.drakon +34 -0
- package/prompts/noloop/flow_no_loop.drakon +26 -0
- package/prompts/noloop/group_stack_by_id.drakon +56 -0
- package/prompts/noloop/increment_if_count.drakon +34 -0
- package/prompts/noloop/merge_incoming_branches.drakon +105 -0
- package/prompts/noloop/recurse_traversal.drakon +88 -0
- package/prompts/noloop/traverse_node.drakon +62 -0
- package/secondary/Secondary.drakon +72 -0
- package/src/browserTools.js +1 -1
- package/src/drakonToPromptStruct.js +4 -3
- package/src/drakonToStruct.js +170 -15
- package/src/drakongen.js +44 -19
- package/src/free.js +69 -0
- package/src/index.js +42 -15
- package/src/main.js +10 -4
- package/src/nodeTools.js +1 -1
- package/src/noloop.js +181 -0
- package/src/printPseudo.js +29 -3
- package/src/structFlow.js +381 -334
- package/src/technicalTree.js +24 -1
- package/src/translate.js +21 -3
- package/src/treeTools.js +21 -0
- package/test_secondary.js +14 -0
- package/.vscode/launch.json +0 -18
- package/exampleproject/.drakontech/history.json +0 -12
- package/exampleproject/.drakontech/opened.txt +0 -1
- package/examples/.drakontech/history.json +0 -124
- package/examples/.drakontech/opened.txt +0 -1
package/browser/drakongen.js
CHANGED
|
@@ -14,7 +14,7 @@ function htmlToString(html) {
|
|
|
14
14
|
|
|
15
15
|
root.childNodes.forEach((node) => {
|
|
16
16
|
if (node.tagName === 'P') {
|
|
17
|
-
output.push(node.textContent
|
|
17
|
+
output.push(node.textContent);
|
|
18
18
|
} else if (node.tagName === 'UL') {
|
|
19
19
|
node.childNodes.forEach((item) => {
|
|
20
20
|
if (item.tagName === 'LI') {
|
|
@@ -39,16 +39,17 @@ const {drakonToStruct} = require("./drakonToStruct");
|
|
|
39
39
|
const {printPseudo, printWithIndent, makeIndent} = require('./printPseudo');
|
|
40
40
|
const {addRange, sortByProperty} = require("./tools")
|
|
41
41
|
|
|
42
|
-
function drakonToPseudocode(drakonJson, name, filename, htmlToString, translate) {
|
|
43
|
-
var diagram = drakonToStruct(drakonJson, name, filename, translate)
|
|
42
|
+
function drakonToPseudocode(drakonJson, name, filename, htmlToString, translate, options) {
|
|
43
|
+
var diagram = drakonToStruct(drakonJson, name, filename, translate, htmlToString, options)
|
|
44
44
|
var lines = []
|
|
45
45
|
|
|
46
46
|
lines.push("## " + translate("Procedure") + " \"" + diagram.name + "\"")
|
|
47
|
+
lines.push("")
|
|
47
48
|
if (diagram.params) {
|
|
48
49
|
lines.push(translate("Parameters") + ":")
|
|
49
50
|
addRange(lines, htmlToString(diagram.params))
|
|
51
|
+
lines.push("")
|
|
50
52
|
}
|
|
51
|
-
lines.push("")
|
|
52
53
|
lines.push(translate("Algorithm") + ":")
|
|
53
54
|
|
|
54
55
|
if (diagram.branches.length === 0) {
|
|
@@ -153,450 +154,953 @@ function createMindNode(name) {
|
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
module.exports = { drakonToPseudocode, mindToTree };
|
|
156
|
-
},{"./drakonToStruct":3,"./printPseudo":
|
|
157
|
+
},{"./drakonToStruct":3,"./printPseudo":7,"./tools":10}],3:[function(require,module,exports){
|
|
157
158
|
const { structFlow, redirectNode } = require("./structFlow");
|
|
158
159
|
const { createError, remove } = require("./tools");
|
|
159
160
|
|
|
160
|
-
var translate
|
|
161
|
-
|
|
162
|
-
function drakonToStruct(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
buildTwoWayConnections(nodes, firstNodeId)
|
|
190
|
-
|
|
191
|
-
rewireSelectsMarkLoops(nodes, filename)
|
|
192
|
-
branches.forEach(branch => checkBranchIsReferenced(branch, firstNodeId, filename))
|
|
193
|
-
rewireShortcircuit(nodes, filename)
|
|
194
|
-
branches.forEach(branch => cutOffBranch(nodes, branch))
|
|
195
|
-
var branchTrees = structFlow(nodes, branches, filename, translate)
|
|
161
|
+
var translate;
|
|
162
|
+
|
|
163
|
+
function drakonToStruct(
|
|
164
|
+
drakonJson,
|
|
165
|
+
name,
|
|
166
|
+
filename,
|
|
167
|
+
translateFunction,
|
|
168
|
+
htmlToString,
|
|
169
|
+
options,
|
|
170
|
+
) {
|
|
171
|
+
options = options || {};
|
|
172
|
+
translate = translateFunction;
|
|
173
|
+
let drakonGraph;
|
|
174
|
+
try {
|
|
175
|
+
drakonJson = drakonJson || "";
|
|
176
|
+
drakonJson = drakonJson.trim();
|
|
177
|
+
drakonJson = drakonJson || "{}";
|
|
178
|
+
drakonGraph = JSON.parse(drakonJson);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
var message = translate("Error parsing JSON") + ": " + error.message;
|
|
181
|
+
throw createError(message, filename);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const nodes = drakonGraph.items || {};
|
|
185
|
+
|
|
186
|
+
var branches = [];
|
|
187
|
+
var firstNodeId = findStartNode(nodes, filename, branches);
|
|
188
|
+
|
|
189
|
+
if (!firstNodeId) {
|
|
196
190
|
return {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
191
|
+
name: name,
|
|
192
|
+
params: drakonGraph.params || "",
|
|
193
|
+
description: drakonGraph.description || "",
|
|
194
|
+
branches: [],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
handleParallel(nodes, undefined, firstNodeId, {}, undefined);
|
|
199
|
+
buildTwoWayConnections(nodes, firstNodeId, htmlToString);
|
|
200
|
+
|
|
201
|
+
rewireSelectsMarkLoops(nodes, filename);
|
|
202
|
+
branches.forEach((branch) =>
|
|
203
|
+
checkBranchIsReferenced(
|
|
204
|
+
branch,
|
|
205
|
+
firstNodeId,
|
|
206
|
+
filename,
|
|
207
|
+
options,
|
|
208
|
+
htmlToString,
|
|
209
|
+
),
|
|
210
|
+
);
|
|
211
|
+
rewireShortcircuit(nodes, filename);
|
|
212
|
+
branches.forEach((branch) => cutOffBranch(nodes, branch));
|
|
213
|
+
var branchTrees = structFlow(nodes, branches, filename, translate, options);
|
|
214
|
+
return {
|
|
215
|
+
name: name,
|
|
216
|
+
params: drakonGraph.params || "",
|
|
217
|
+
description: drakonGraph.description || "",
|
|
218
|
+
branches: branchTrees,
|
|
219
|
+
secondary: findSecondary(branchTrees, options, htmlToString),
|
|
220
|
+
};
|
|
202
221
|
}
|
|
203
222
|
|
|
204
|
-
function
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if (!firstNodeId) {
|
|
220
|
-
return undefined
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
buildTwoWayConnections(nodes, firstNodeId)
|
|
224
|
-
|
|
225
|
-
rewireSelectsMarkLoops(nodes, filename)
|
|
226
|
-
rewireShortcircuit(nodes, filename)
|
|
227
|
-
branches.forEach(branch => checkBranchIsReferenced(branch, firstNodeId, filename))
|
|
228
|
-
branches.forEach(branch => cutOffBranch(nodes, branch))
|
|
229
|
-
|
|
230
|
-
var branchTrees = structFlow(nodes, branches, filename, translate)
|
|
223
|
+
function findSecondary(branchTrees, options, htmlToString) {
|
|
224
|
+
if (!options || !options.secondary) {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
var ordinal = 0;
|
|
228
|
+
for (var branch of branchTrees) {
|
|
229
|
+
var name = htmlToString(branch.name)[0];
|
|
230
|
+
if (name === options.secondary) {
|
|
231
|
+
return ordinal;
|
|
232
|
+
}
|
|
233
|
+
ordinal++;
|
|
234
|
+
}
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
231
237
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
+
function handleParallel(nodes, prevNode, nodeId, visited, proc) {
|
|
239
|
+
if (!nodeId) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
var node = nodes[nodeId];
|
|
243
|
+
if (node.type === "parend") {
|
|
244
|
+
if (!proc) {
|
|
245
|
+
throw new Error("handleParallel: no proc for parend");
|
|
246
|
+
}
|
|
247
|
+
var endId = proc.end;
|
|
248
|
+
var end;
|
|
249
|
+
if (endId) {
|
|
250
|
+
end = nodes[endId];
|
|
251
|
+
} else {
|
|
252
|
+
end = {
|
|
253
|
+
type: "end",
|
|
254
|
+
id: proc.id + "-" + proc.ordinal + "-end",
|
|
255
|
+
prev: [],
|
|
256
|
+
};
|
|
257
|
+
nodes[end.id] = end;
|
|
258
|
+
proc.end = end.id;
|
|
259
|
+
proc.next = node.one;
|
|
260
|
+
}
|
|
261
|
+
redirectNode(nodes, prevNode, nodeId, end.id);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (nodeId in visited) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
visited[nodeId] = true;
|
|
268
|
+
if (node.type === "parbegin") {
|
|
269
|
+
node.procs = [];
|
|
270
|
+
var ordinal = 0;
|
|
271
|
+
var current = node;
|
|
272
|
+
while (true) {
|
|
273
|
+
var start = {
|
|
274
|
+
id: nodeId + "-" + ordinal + "-start",
|
|
275
|
+
type: "action",
|
|
276
|
+
prev: [],
|
|
277
|
+
one: current.one,
|
|
278
|
+
};
|
|
279
|
+
nodes[start.id] = start;
|
|
280
|
+
var childProc = {
|
|
281
|
+
id: nodeId,
|
|
282
|
+
ordinal: ordinal,
|
|
283
|
+
start: start.id,
|
|
284
|
+
};
|
|
285
|
+
var next = current.two;
|
|
286
|
+
node.procs.push(childProc);
|
|
287
|
+
handleParallel(nodes, start, start.one, {}, childProc);
|
|
288
|
+
delete current.one;
|
|
289
|
+
delete current.two;
|
|
290
|
+
if (!next) {
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
current = nodes[next];
|
|
294
|
+
ordinal++;
|
|
295
|
+
}
|
|
296
|
+
node.one = node.procs[0].next;
|
|
297
|
+
handleParallel(nodes, node, node.one, visited, proc);
|
|
298
|
+
} else {
|
|
299
|
+
handleParallel(nodes, node, node.one, visited, proc);
|
|
300
|
+
handleParallel(nodes, node, node.two, visited, proc);
|
|
301
|
+
}
|
|
238
302
|
}
|
|
239
303
|
|
|
304
|
+
function drakonToGraph(drakonJson, name, filename, translateFunction) {
|
|
305
|
+
translate = translateFunction;
|
|
306
|
+
let drakonGraph;
|
|
307
|
+
try {
|
|
308
|
+
drakonGraph = JSON.parse(drakonJson);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
var message = translate("Error parsing JSON") + ": " + error.message;
|
|
311
|
+
throw createError(message, filename);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const nodes = drakonGraph.items || {};
|
|
315
|
+
|
|
316
|
+
var branches = [];
|
|
317
|
+
var firstNodeId = findStartNode(nodes, filename, branches);
|
|
318
|
+
|
|
319
|
+
if (!firstNodeId) {
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
buildTwoWayConnections(nodes, firstNodeId);
|
|
324
|
+
|
|
325
|
+
rewireSelectsMarkLoops(nodes, filename);
|
|
326
|
+
rewireShortcircuit(nodes, filename);
|
|
327
|
+
branches.forEach((branch) =>
|
|
328
|
+
checkBranchIsReferenced(
|
|
329
|
+
branch,
|
|
330
|
+
firstNodeId,
|
|
331
|
+
filename,
|
|
332
|
+
undefined,
|
|
333
|
+
undefined,
|
|
334
|
+
),
|
|
335
|
+
);
|
|
336
|
+
branches.forEach((branch) => cutOffBranch(nodes, branch));
|
|
337
|
+
|
|
338
|
+
var branchTrees = structFlow(nodes, branches, filename, translate);
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
name: name,
|
|
342
|
+
params: drakonGraph.params || "",
|
|
343
|
+
description: drakonGraph.description || "",
|
|
344
|
+
branches: branchTrees,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
240
347
|
|
|
241
|
-
function checkBranchIsReferenced(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
348
|
+
function checkBranchIsReferenced(
|
|
349
|
+
branch,
|
|
350
|
+
firstNodeId,
|
|
351
|
+
filename,
|
|
352
|
+
options,
|
|
353
|
+
htmlToString,
|
|
354
|
+
) {
|
|
355
|
+
if (branch.id === firstNodeId) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (options && htmlToString) {
|
|
359
|
+
var branchName = htmlToString(branch.content)[0];
|
|
360
|
+
if (branchName === options.secondary) {
|
|
361
|
+
if (branch.prev.length > 0) {
|
|
362
|
+
throw createError(
|
|
363
|
+
translate("A secondary branch is referenced"),
|
|
364
|
+
filename,
|
|
365
|
+
branch.id,
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
} else {
|
|
369
|
+
if (branch.prev.length === 0) {
|
|
370
|
+
throw createError(
|
|
371
|
+
translate("A silhouette branch is not referenced"),
|
|
372
|
+
filename,
|
|
373
|
+
branch.id,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
248
378
|
}
|
|
249
379
|
|
|
250
380
|
function cutOffBranch(nodes, branch) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
381
|
+
var end = {
|
|
382
|
+
type: "end",
|
|
383
|
+
id: branch.id + "-end",
|
|
384
|
+
prev: [],
|
|
385
|
+
};
|
|
386
|
+
nodes[end.id] = end;
|
|
387
|
+
branch.next = branch.one;
|
|
388
|
+
var addresses = [];
|
|
389
|
+
traverseToHitBranch(nodes, branch.id, {}, (prev, node) =>
|
|
390
|
+
addFakeEnd(nodes, prev, node, end, addresses),
|
|
391
|
+
);
|
|
260
392
|
}
|
|
261
393
|
|
|
262
394
|
function traverseToHitBranch(nodes, nodeId, visited, action) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
395
|
+
if (!nodeId) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (nodeId in visited) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
visited[nodeId] = true;
|
|
402
|
+
var node = nodes[nodeId];
|
|
403
|
+
if (!node) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (node.one) {
|
|
407
|
+
var one = nodes[node.one];
|
|
408
|
+
if (one.type === "branch") {
|
|
409
|
+
action(node, one);
|
|
410
|
+
} else {
|
|
411
|
+
traverseToHitBranch(nodes, node.one, visited, action);
|
|
275
412
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
413
|
+
}
|
|
414
|
+
if (node.two) {
|
|
415
|
+
var two = nodes[node.two];
|
|
416
|
+
if (two.type === "branch") {
|
|
417
|
+
action(node, two);
|
|
418
|
+
} else {
|
|
419
|
+
traverseToHitBranch(nodes, node.two, visited, action);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
284
422
|
}
|
|
285
423
|
|
|
286
|
-
var idCounter = 1000
|
|
424
|
+
var idCounter = 1000;
|
|
287
425
|
function addFakeEnd(nodes, prev, node, end, addresses) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function buildTwoWayConnections(nodes, firstNodeId) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
426
|
+
var lastAddress = undefined;
|
|
427
|
+
if (addresses.length > 0) {
|
|
428
|
+
lastAddress = addresses[addresses.length - 1];
|
|
429
|
+
}
|
|
430
|
+
var address;
|
|
431
|
+
if (lastAddress && lastAddress.branch === node.id) {
|
|
432
|
+
address = lastAddress;
|
|
433
|
+
} else {
|
|
434
|
+
address = {
|
|
435
|
+
type: "address",
|
|
436
|
+
content: node.content,
|
|
437
|
+
id: "ad-" + idCounter,
|
|
438
|
+
branch: node.id,
|
|
439
|
+
one: end.id,
|
|
440
|
+
prev: [],
|
|
441
|
+
};
|
|
442
|
+
idCounter++;
|
|
443
|
+
nodes[address.id] = address;
|
|
444
|
+
end.prev.push(address.id);
|
|
445
|
+
addresses.push(address);
|
|
446
|
+
node.prev.push(address.id);
|
|
447
|
+
}
|
|
448
|
+
redirectNode(nodes, prev, node.id, address.id);
|
|
449
|
+
address.prev.push(prev.id);
|
|
450
|
+
node.prev = remove(node.prev, prev.id);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function buildTwoWayConnections(nodes, firstNodeId, htmlToString) {
|
|
454
|
+
for (var id in nodes) {
|
|
455
|
+
var node = nodes[id];
|
|
456
|
+
node.id = id;
|
|
457
|
+
node.prev = [];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
var visitor = function (nodes, node) {
|
|
461
|
+
return connectBack(nodes, node, htmlToString);
|
|
462
|
+
};
|
|
321
463
|
|
|
322
|
-
|
|
464
|
+
traverse(nodes, firstNodeId, {}, visitor);
|
|
323
465
|
}
|
|
324
466
|
|
|
325
467
|
function findStartNode(nodes, filename, branches) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
468
|
+
var firstNodeId = undefined;
|
|
469
|
+
var minBranchId = 10000;
|
|
470
|
+
for (var id in nodes) {
|
|
471
|
+
var node = nodes[id];
|
|
472
|
+
if (node.type === "branch") {
|
|
473
|
+
if (node.branchId < minBranchId) {
|
|
474
|
+
firstNodeId = id;
|
|
475
|
+
minBranchId = node.branchId;
|
|
476
|
+
}
|
|
477
|
+
branches.push(node);
|
|
478
|
+
} else if (node.type === "select") {
|
|
479
|
+
if (!node.content) {
|
|
480
|
+
throw createError(
|
|
481
|
+
translate("A Select icon must have content"),
|
|
482
|
+
filename,
|
|
483
|
+
id,
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
node.cases = [];
|
|
487
|
+
} else if (node.type === "loopbegin") {
|
|
488
|
+
if (!node.content) {
|
|
489
|
+
throw createError(
|
|
490
|
+
translate("A Loop begin icon must have content"),
|
|
491
|
+
filename,
|
|
492
|
+
id,
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
} else if (node.type === "question") {
|
|
496
|
+
if (!node.content) {
|
|
497
|
+
throw createError(
|
|
498
|
+
translate("A Question icon must have content"),
|
|
499
|
+
filename,
|
|
500
|
+
id,
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
} else if (node.final) {
|
|
504
|
+
delete node.one
|
|
505
|
+
delete node.two
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return firstNodeId;
|
|
353
510
|
}
|
|
354
511
|
|
|
355
512
|
function rewireSelectsMarkLoops(nodes, filename) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
513
|
+
for (var id of Object.keys(nodes)) {
|
|
514
|
+
var node = nodes[id];
|
|
515
|
+
if (!node) {
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
if (node.type === "select") {
|
|
519
|
+
rewireSelect(nodes, node, filename);
|
|
520
|
+
} else if (node.type === "loopbegin") {
|
|
521
|
+
markLoopBody(nodes, node, filename);
|
|
364
522
|
}
|
|
523
|
+
}
|
|
365
524
|
}
|
|
366
525
|
|
|
367
526
|
function rewireSelect(nodes, selectNode, filename) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
527
|
+
var caseNodeId = selectNode.one;
|
|
528
|
+
var caseNode0 = nodes[caseNodeId];
|
|
529
|
+
while (caseNodeId) {
|
|
530
|
+
var caseNode = nodes[caseNodeId];
|
|
531
|
+
caseNodeId = caseNode.two;
|
|
532
|
+
if (caseNode.content) {
|
|
533
|
+
caseNode.type = "question";
|
|
534
|
+
caseNode.flag1 = 1;
|
|
535
|
+
caseNode.content = {
|
|
536
|
+
operator: "equal",
|
|
537
|
+
left: selectNode.content,
|
|
538
|
+
right: caseNode.content,
|
|
539
|
+
};
|
|
540
|
+
if (!caseNode.two) {
|
|
541
|
+
var errorId = caseNode.id + "-unexpected";
|
|
542
|
+
var errorAction = insertIcon(
|
|
543
|
+
nodes,
|
|
544
|
+
"error",
|
|
545
|
+
errorId,
|
|
546
|
+
selectNode.content,
|
|
547
|
+
);
|
|
548
|
+
errorAction.message = translate("Unexpected case value");
|
|
549
|
+
|
|
550
|
+
caseNode.two = errorId;
|
|
551
|
+
errorAction.prev.push(caseNode.id);
|
|
552
|
+
errorAction.one = caseNode.one;
|
|
553
|
+
|
|
554
|
+
var next = nodes[caseNode.one];
|
|
555
|
+
next.prev.push(errorId);
|
|
556
|
+
}
|
|
557
|
+
} else {
|
|
558
|
+
if (caseNode.two) {
|
|
559
|
+
throw createError(
|
|
560
|
+
translate("Only the rightmost Case icon can be empty"),
|
|
561
|
+
filename,
|
|
562
|
+
caseNode.id,
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
removeNodeOne(nodes, caseNode.id);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
caseNode0.side = selectNode.side;
|
|
569
|
+
removeNodeOne(nodes, selectNode.id);
|
|
396
570
|
}
|
|
397
571
|
|
|
398
572
|
function insertIcon(nodes, type, id, content) {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
573
|
+
var node = {
|
|
574
|
+
type: type,
|
|
575
|
+
id: id,
|
|
576
|
+
content: content,
|
|
577
|
+
prev: [],
|
|
578
|
+
};
|
|
579
|
+
nodes[id] = node;
|
|
580
|
+
return node;
|
|
407
581
|
}
|
|
408
582
|
|
|
409
583
|
function removeNodeOne(nodes, nodeId) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
584
|
+
var node = nodes[nodeId];
|
|
585
|
+
redirectPrev(nodes, node, node.one);
|
|
586
|
+
redirectNext(nodes, node, node.one);
|
|
587
|
+
delete nodes[nodeId];
|
|
414
588
|
}
|
|
415
589
|
|
|
416
590
|
function removeFromNext(node, next) {
|
|
417
|
-
|
|
591
|
+
next.prev = next.prev.filter((prevId) => prevId !== node.id);
|
|
418
592
|
}
|
|
419
593
|
|
|
420
594
|
function redirectPrev(nodes, node, newTarget) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
}
|
|
595
|
+
for (var prevId of node.prev) {
|
|
596
|
+
var prev = nodes[prevId];
|
|
597
|
+
if (prev.one === node.id) {
|
|
598
|
+
prev.one = newTarget;
|
|
599
|
+
}
|
|
600
|
+
if (prev.two === node.id) {
|
|
601
|
+
prev.two = newTarget;
|
|
429
602
|
}
|
|
603
|
+
}
|
|
430
604
|
}
|
|
431
605
|
|
|
432
606
|
function redirectNext(nodes, node, newTarget) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
607
|
+
var target = nodes[newTarget];
|
|
608
|
+
removeFromNext(node, target);
|
|
609
|
+
for (var prevId of node.prev) {
|
|
610
|
+
target.prev.push(prevId);
|
|
611
|
+
}
|
|
438
612
|
}
|
|
439
613
|
|
|
440
614
|
function rewireShortcircuit(nodes) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
615
|
+
while (findShortcusts(nodes)) {}
|
|
444
616
|
}
|
|
445
617
|
|
|
446
618
|
function findShortcusts(nodes) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
619
|
+
for (var id in nodes) {
|
|
620
|
+
var node = nodes[id];
|
|
621
|
+
if (node.type === "question") {
|
|
622
|
+
var andOperand = findAndOperand(nodes, node);
|
|
623
|
+
if (andOperand) {
|
|
624
|
+
writeAndShortcut(nodes, node, andOperand);
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
var orOperand = findOrOperand(nodes, node);
|
|
628
|
+
if (orOperand) {
|
|
629
|
+
writeOrShortcut(nodes, node, orOperand);
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return false;
|
|
463
635
|
}
|
|
464
636
|
|
|
465
637
|
function findAndOperand(nodes, node) {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
638
|
+
var below = nodes[node.one];
|
|
639
|
+
if (below.type === "question") {
|
|
640
|
+
if (below.prev.length === 1 && below.two === node.two) {
|
|
641
|
+
return below;
|
|
471
642
|
}
|
|
472
|
-
|
|
643
|
+
}
|
|
644
|
+
return undefined;
|
|
473
645
|
}
|
|
474
646
|
|
|
475
647
|
function findOrOperand(nodes, node) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}
|
|
648
|
+
var right = nodes[node.two];
|
|
649
|
+
if (right.type === "question") {
|
|
650
|
+
if (right.prev.length === 1 && right.one === node.one) {
|
|
651
|
+
return right;
|
|
481
652
|
}
|
|
482
|
-
|
|
653
|
+
}
|
|
654
|
+
return undefined;
|
|
483
655
|
}
|
|
484
656
|
|
|
485
657
|
function writeAndShortcut(nodes, node, andOperand) {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
658
|
+
var right = nodes[node.two];
|
|
659
|
+
var down = nodes[andOperand.one];
|
|
660
|
+
removeFromNext(andOperand, right);
|
|
661
|
+
removeFromNext(andOperand, down);
|
|
662
|
+
node.content = {
|
|
663
|
+
operator: "and",
|
|
664
|
+
left: normalizeContent(node),
|
|
665
|
+
right: normalizeContent(andOperand),
|
|
666
|
+
};
|
|
667
|
+
node.one = down.id;
|
|
668
|
+
node.flag1 = 1;
|
|
669
|
+
normalizeAnd(node);
|
|
670
|
+
down.prev.push(node.id);
|
|
671
|
+
delete nodes[andOperand.id];
|
|
499
672
|
}
|
|
500
673
|
|
|
501
674
|
function writeOrShortcut(nodes, node, orOperand) {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
675
|
+
var right = nodes[orOperand.two];
|
|
676
|
+
var down = nodes[orOperand.one];
|
|
677
|
+
removeFromNext(orOperand, right);
|
|
678
|
+
removeFromNext(orOperand, down);
|
|
679
|
+
node.content = {
|
|
680
|
+
operator: "or",
|
|
681
|
+
left: normalizeContent(node),
|
|
682
|
+
right: normalizeContent(orOperand),
|
|
683
|
+
};
|
|
684
|
+
node.two = right.id;
|
|
685
|
+
node.flag1 = 1;
|
|
686
|
+
normalizeOr(node);
|
|
687
|
+
right.prev.push(node.id);
|
|
688
|
+
delete nodes[orOperand.id];
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function normalizeAnd(node) {
|
|
692
|
+
var op = node.content;
|
|
693
|
+
var left = op.left;
|
|
694
|
+
var right = op.right;
|
|
695
|
+
if (left.operator === "not" && right.operator === "not") {
|
|
506
696
|
node.content = {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
node.
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
697
|
+
operator: "or",
|
|
698
|
+
left: left.operand,
|
|
699
|
+
right: right.operand,
|
|
700
|
+
};
|
|
701
|
+
node.flag1 = 0;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function normalizeOr(node) {
|
|
706
|
+
var op = node.content;
|
|
707
|
+
var left = op.left;
|
|
708
|
+
var right = op.right;
|
|
709
|
+
if (left.operator === "not" && right.operator === "not") {
|
|
710
|
+
node.content = {
|
|
711
|
+
operator: "and",
|
|
712
|
+
left: left.operand,
|
|
713
|
+
right: right.operand,
|
|
714
|
+
};
|
|
715
|
+
node.flag1 = 0;
|
|
716
|
+
}
|
|
515
717
|
}
|
|
516
718
|
|
|
517
719
|
function normalizeContent(question) {
|
|
518
|
-
|
|
519
|
-
|
|
720
|
+
if (question.flag1 === 1) {
|
|
721
|
+
return question.content;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return {
|
|
725
|
+
operator: "not",
|
|
726
|
+
operand: question.content,
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function traverse(nodes, nodeId, visited, action) {
|
|
731
|
+
if (!nodeId) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (nodeId in visited) {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
visited[nodeId] = true;
|
|
739
|
+
var node = nodes[nodeId];
|
|
740
|
+
action(nodes, node);
|
|
741
|
+
traverse(nodes, node.one, visited, action);
|
|
742
|
+
traverse(nodes, node.two, visited, action);
|
|
743
|
+
if (node.procs) {
|
|
744
|
+
for (var proc of node.procs) {
|
|
745
|
+
traverse(nodes, proc.start, visited, action);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function connectBack(nodes, node, htmlToString) {
|
|
751
|
+
if (node.one) {
|
|
752
|
+
var one = nodes[node.one];
|
|
753
|
+
one.prev.push(node.id);
|
|
754
|
+
}
|
|
755
|
+
if (node.two) {
|
|
756
|
+
var two = nodes[node.two];
|
|
757
|
+
two.prev.push(node.id);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
if (node.side) {
|
|
761
|
+
var side = nodes[node.side].content;
|
|
762
|
+
if (side) {
|
|
763
|
+
node.side = decodeSide(side, htmlToString);
|
|
764
|
+
} else {
|
|
765
|
+
delete node.side;
|
|
520
766
|
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
521
769
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
770
|
+
function decodeSide(content, htmlToString) {
|
|
771
|
+
var text = htmlToString(content);
|
|
772
|
+
var oneLine = text.join(" ");
|
|
773
|
+
if (oneLine.indexOf("=") === -1) {
|
|
774
|
+
return translate("Do for") + " " + oneLine;
|
|
775
|
+
} else {
|
|
776
|
+
return translate("Start at") + " " + oneLine;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
function markLoopBody(nodes, start, filename) {
|
|
781
|
+
var nextNodeId = start.one;
|
|
782
|
+
while (nextNodeId) {
|
|
783
|
+
var current = nodes[nextNodeId];
|
|
784
|
+
nextNodeId = current.one;
|
|
785
|
+
current.parentLoopId = start.id;
|
|
786
|
+
if (current.type === "loopbegin") {
|
|
787
|
+
nextNodeId = markLoopBody(nodes, current, filename);
|
|
788
|
+
} else if (current.type === "loopend") {
|
|
789
|
+
start.end = current.id;
|
|
790
|
+
start.next = current.one;
|
|
791
|
+
current.start = start.id;
|
|
792
|
+
return nextNodeId;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
throw createError(translate("Loop end expected here"), filename, start.one);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
module.exports = { drakonToStruct, drakonToGraph };
|
|
799
|
+
|
|
800
|
+
},{"./structFlow":8,"./tools":10}],4:[function(require,module,exports){
|
|
801
|
+
const { drakonToPseudocode, mindToTree } = require("./drakonToPromptStruct");
|
|
802
|
+
const { htmlToString } = require("./browserTools");
|
|
803
|
+
const { setUpLanguage, translate } = require("./translate");
|
|
804
|
+
const { drakonToStruct } = require("./drakonToStruct");
|
|
805
|
+
const { freeDiagramToText } = require("./free");
|
|
806
|
+
|
|
807
|
+
window.drakongen = {
|
|
808
|
+
toPseudocode: function (drakonJson, name, filename, language) {
|
|
809
|
+
setUpLanguage(language);
|
|
810
|
+
return drakonToPseudocode(
|
|
811
|
+
drakonJson,
|
|
812
|
+
name,
|
|
813
|
+
filename,
|
|
814
|
+
htmlToString,
|
|
815
|
+
translate,
|
|
816
|
+
).text;
|
|
817
|
+
},
|
|
818
|
+
|
|
819
|
+
toMindTree: function (mindJson, name, filename, language) {
|
|
820
|
+
setUpLanguage(language);
|
|
821
|
+
var result = mindToTree(mindJson, name, filename, htmlToString);
|
|
822
|
+
return result.text;
|
|
823
|
+
},
|
|
824
|
+
|
|
825
|
+
freeToText: function (freeJson, name, filename, language) {
|
|
826
|
+
setUpLanguage(language);
|
|
827
|
+
var result = freeDiagramToText(
|
|
828
|
+
freeJson,
|
|
829
|
+
name,
|
|
830
|
+
filename,
|
|
831
|
+
translate,
|
|
832
|
+
htmlToString,
|
|
833
|
+
);
|
|
834
|
+
return result.text;
|
|
835
|
+
},
|
|
836
|
+
|
|
837
|
+
toTree: function (drakonJson, name, filename, language, options) {
|
|
838
|
+
setUpLanguage(language);
|
|
839
|
+
var result = drakonToStruct(
|
|
840
|
+
drakonJson,
|
|
841
|
+
name,
|
|
842
|
+
filename,
|
|
843
|
+
translate,
|
|
844
|
+
htmlToString,
|
|
845
|
+
options,
|
|
846
|
+
);
|
|
847
|
+
return JSON.stringify(result, null, 4);
|
|
848
|
+
},
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
},{"./browserTools":1,"./drakonToPromptStruct":2,"./drakonToStruct":3,"./free":5,"./translate":11}],5:[function(require,module,exports){
|
|
852
|
+
var {addRange} = require("./tools")
|
|
853
|
+
const { createError } = require("./tools");
|
|
854
|
+
|
|
855
|
+
var translate
|
|
856
|
+
|
|
857
|
+
function compareVertically(box1, box2) {
|
|
858
|
+
if (box1.top + box1.height <= box2.top) return -1;
|
|
859
|
+
if (box2.top + box2.height <= box1.top) return 1;
|
|
860
|
+
return 0;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
function compareHorizontally(box1, box2) {
|
|
864
|
+
if (box1.left + box1.width <= box2.left) return -1;
|
|
865
|
+
if (box2.left + box2.width <= box1.left) return 1;
|
|
866
|
+
return 0;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function byTopLeft(box1, box2) {
|
|
870
|
+
var vertical = compareVertically(box1, box2)
|
|
871
|
+
if (vertical == 0) {
|
|
872
|
+
return compareHorizontally(box1, box2)
|
|
525
873
|
}
|
|
874
|
+
return vertical
|
|
526
875
|
}
|
|
527
876
|
|
|
877
|
+
function parseDiagram(freeJson, filename) {
|
|
878
|
+
let diagram;
|
|
879
|
+
try {
|
|
880
|
+
freeJson = freeJson || ""
|
|
881
|
+
freeJson = freeJson.trim()
|
|
882
|
+
freeJson = freeJson || "{}"
|
|
883
|
+
diagram = JSON.parse(freeJson);
|
|
884
|
+
} catch (error) {
|
|
885
|
+
var message = translate("Error parsing JSON") + ": " + error.message
|
|
886
|
+
throw createError(message, filename)
|
|
887
|
+
}
|
|
888
|
+
return diagram
|
|
889
|
+
}
|
|
528
890
|
|
|
529
|
-
function
|
|
530
|
-
|
|
531
|
-
|
|
891
|
+
function sortedItems(diagram) {
|
|
892
|
+
var items = diagram.items || {};
|
|
893
|
+
var result = [];
|
|
894
|
+
for (var id in items) {
|
|
895
|
+
var item = items[id];
|
|
896
|
+
if (item.content && item.top && item.left && item.width && item.height) {
|
|
897
|
+
result.push(item);
|
|
898
|
+
}
|
|
532
899
|
}
|
|
900
|
+
result.sort(byTopLeft);
|
|
901
|
+
return result;
|
|
902
|
+
}
|
|
533
903
|
|
|
534
|
-
|
|
535
|
-
|
|
904
|
+
function freeDiagramToText(freeJson, name, filename, translateFunction, htmlToString) {
|
|
905
|
+
translate = translateFunction
|
|
906
|
+
var diagram = parseDiagram(freeJson, filename)
|
|
907
|
+
var sorted = sortedItems(diagram)
|
|
908
|
+
var lines = []
|
|
909
|
+
lines.push("## " + name)
|
|
910
|
+
lines.push("")
|
|
911
|
+
for (var item of sorted) {
|
|
912
|
+
var content = htmlToString(item.content)
|
|
913
|
+
addRange(lines, content)
|
|
914
|
+
lines.push("")
|
|
536
915
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
action(nodes, node)
|
|
540
|
-
traverse(nodes, node.one, visited, action)
|
|
541
|
-
traverse(nodes, node.two, visited, action)
|
|
916
|
+
var text = lines.join("\n")
|
|
917
|
+
return {text:text}
|
|
542
918
|
}
|
|
543
919
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
920
|
+
module.exports = {freeDiagramToText}
|
|
921
|
+
},{"./tools":10}],6:[function(require,module,exports){
|
|
922
|
+
"use strict";
|
|
923
|
+
|
|
924
|
+
function decrement_if_count(context, node) {
|
|
925
|
+
var i;
|
|
926
|
+
var if_id;
|
|
927
|
+
var if_node;
|
|
928
|
+
|
|
929
|
+
for (i = 0; i < node.stack.length; i++) {
|
|
930
|
+
if_id = node.stack[i];
|
|
931
|
+
if_node = context.nodes[if_id];
|
|
932
|
+
if_node.branching--;
|
|
548
933
|
}
|
|
549
|
-
if (node.two) {
|
|
550
|
-
var two = nodes[node.two]
|
|
551
|
-
two.prev.push(node.id)
|
|
552
|
-
}
|
|
553
934
|
}
|
|
554
935
|
|
|
555
|
-
function
|
|
556
|
-
var
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
936
|
+
function flow_no_loop(nodes, start_node_id) {
|
|
937
|
+
var context;
|
|
938
|
+
|
|
939
|
+
context = {
|
|
940
|
+
nodes: nodes
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
traverse_node(
|
|
944
|
+
context,
|
|
945
|
+
start_node_id,
|
|
946
|
+
[]
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
function group_stack_by_id(stack) {
|
|
951
|
+
var counts_by_id;
|
|
952
|
+
var i;
|
|
953
|
+
var element;
|
|
954
|
+
var existing;
|
|
955
|
+
|
|
956
|
+
counts_by_id = {};
|
|
957
|
+
|
|
958
|
+
for (i = 0; i < stack.length; i++) {
|
|
959
|
+
element = stack[i];
|
|
960
|
+
|
|
961
|
+
if (element in counts_by_id) {
|
|
962
|
+
existing = counts_by_id[element];
|
|
963
|
+
} else {
|
|
964
|
+
existing = 0;
|
|
568
965
|
}
|
|
966
|
+
|
|
967
|
+
counts_by_id[element] = existing + 1;
|
|
569
968
|
}
|
|
570
|
-
|
|
969
|
+
|
|
970
|
+
return counts_by_id;
|
|
571
971
|
}
|
|
572
972
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
973
|
+
function increment_if_count(context, node) {
|
|
974
|
+
var i;
|
|
975
|
+
var if_id;
|
|
976
|
+
var if_node;
|
|
977
|
+
|
|
978
|
+
for (i = 0; i < node.stack.length; i++) {
|
|
979
|
+
if_id = node.stack[i];
|
|
980
|
+
if_node = context.nodes[if_id];
|
|
981
|
+
if_node.branching++;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
579
984
|
|
|
985
|
+
function merge_incoming_branches(context, node_id, node, stack) {
|
|
986
|
+
var common;
|
|
987
|
+
var counts_by_id;
|
|
988
|
+
var processed_stack;
|
|
989
|
+
var ids;
|
|
990
|
+
var i;
|
|
991
|
+
var id;
|
|
992
|
+
var count;
|
|
993
|
+
var if_node;
|
|
580
994
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
995
|
+
common = node.stack.concat(stack);
|
|
996
|
+
counts_by_id = group_stack_by_id(common);
|
|
997
|
+
processed_stack = [];
|
|
998
|
+
|
|
999
|
+
ids = Object.keys(counts_by_id);
|
|
1000
|
+
|
|
1001
|
+
for (i = 0; i < ids.length; i++) {
|
|
1002
|
+
id = ids[i];
|
|
1003
|
+
count = counts_by_id[id];
|
|
1004
|
+
|
|
1005
|
+
if_node = context.nodes[id];
|
|
1006
|
+
|
|
1007
|
+
if (!if_node.next) {
|
|
1008
|
+
if (if_node.branching === 1) {
|
|
1009
|
+
if_node.next = node_id;
|
|
1010
|
+
} else {
|
|
1011
|
+
if_node.branching -= count - 1;
|
|
1012
|
+
|
|
1013
|
+
if (if_node.branching === 1) {
|
|
1014
|
+
if_node.next = node_id;
|
|
1015
|
+
} else {
|
|
1016
|
+
processed_stack.push(id);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
586
1021
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
var result = mindToTree(mindJson, name, filename, htmlToString)
|
|
590
|
-
return result.text
|
|
591
|
-
},
|
|
1022
|
+
node.stack = processed_stack;
|
|
1023
|
+
}
|
|
592
1024
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
1025
|
+
function recurse_traversal(context, node_id, node) {
|
|
1026
|
+
var stack1;
|
|
1027
|
+
var stack2;
|
|
1028
|
+
|
|
1029
|
+
if (node.type === "question") {
|
|
1030
|
+
increment_if_count(
|
|
1031
|
+
context,
|
|
1032
|
+
node
|
|
1033
|
+
);
|
|
1034
|
+
|
|
1035
|
+
stack1 = node.stack.slice();
|
|
1036
|
+
stack1.push(node_id);
|
|
1037
|
+
|
|
1038
|
+
stack2 = node.stack.slice();
|
|
1039
|
+
stack2.push(node_id);
|
|
1040
|
+
|
|
1041
|
+
traverse_node(
|
|
1042
|
+
context,
|
|
1043
|
+
node.one,
|
|
1044
|
+
stack1
|
|
1045
|
+
);
|
|
1046
|
+
|
|
1047
|
+
traverse_node(
|
|
1048
|
+
context,
|
|
1049
|
+
node.two,
|
|
1050
|
+
stack2
|
|
1051
|
+
);
|
|
1052
|
+
} else {
|
|
1053
|
+
if (node.final) {
|
|
1054
|
+
decrement_if_count(
|
|
1055
|
+
context,
|
|
1056
|
+
node
|
|
1057
|
+
);
|
|
1058
|
+
} else {
|
|
1059
|
+
stack1 = node.stack.slice();
|
|
1060
|
+
|
|
1061
|
+
traverse_node(
|
|
1062
|
+
context,
|
|
1063
|
+
node.one,
|
|
1064
|
+
stack1
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
597
1067
|
}
|
|
598
1068
|
}
|
|
599
|
-
|
|
1069
|
+
|
|
1070
|
+
function traverse_node(context, node_id, stack) {
|
|
1071
|
+
var node;
|
|
1072
|
+
|
|
1073
|
+
if (node_id) {
|
|
1074
|
+
node = context.nodes[node_id];
|
|
1075
|
+
|
|
1076
|
+
if (!node.stack) {
|
|
1077
|
+
node.stack = [];
|
|
1078
|
+
node.refs = node.prev.length;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
node.refs--;
|
|
1082
|
+
|
|
1083
|
+
merge_incoming_branches(
|
|
1084
|
+
context,
|
|
1085
|
+
node_id,
|
|
1086
|
+
node,
|
|
1087
|
+
stack
|
|
1088
|
+
);
|
|
1089
|
+
|
|
1090
|
+
if (!(node.refs > 0)) {
|
|
1091
|
+
recurse_traversal(
|
|
1092
|
+
context,
|
|
1093
|
+
node_id,
|
|
1094
|
+
node
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
module.exports = {
|
|
1101
|
+
flow_no_loop: flow_no_loop
|
|
1102
|
+
};
|
|
1103
|
+
},{}],7:[function(require,module,exports){
|
|
600
1104
|
var {addRange} = require("./tools")
|
|
601
1105
|
|
|
602
1106
|
function makeIndent(depth) {
|
|
@@ -609,8 +1113,11 @@ function printWithIndent(lines, indent, output) {
|
|
|
609
1113
|
}
|
|
610
1114
|
|
|
611
1115
|
function printPseudo(algorithm, translate, output, htmlToString) {
|
|
612
|
-
function printStructuredContent(content, indent, output) {
|
|
1116
|
+
function printStructuredContent(content, indent, output, side) {
|
|
613
1117
|
var lines = printStructuredContentNoIdent(content)
|
|
1118
|
+
if (side) {
|
|
1119
|
+
lines[0] = side + ": " + lines[0]
|
|
1120
|
+
}
|
|
614
1121
|
printWithIndent(lines, indent, output)
|
|
615
1122
|
}
|
|
616
1123
|
|
|
@@ -674,19 +1181,39 @@ function printPseudo(algorithm, translate, output, htmlToString) {
|
|
|
674
1181
|
printError(step, indent, output)
|
|
675
1182
|
} else if (step.type === "break") {
|
|
676
1183
|
output.push(indent + translate("break"))
|
|
1184
|
+
} else if (step.type === "parbegin") {
|
|
1185
|
+
printParbegin(step, depth, output)
|
|
677
1186
|
} else {
|
|
678
1187
|
printOther(step, indent, output)
|
|
679
1188
|
}
|
|
680
1189
|
}
|
|
681
1190
|
}
|
|
1191
|
+
|
|
1192
|
+
function printParbegin(step, depth, output) {
|
|
1193
|
+
const indent2 = makeIndent(depth + 1)
|
|
1194
|
+
const indent = makeIndent(depth)
|
|
1195
|
+
printWithIndent([translate("Group of parallel processes")], indent, output)
|
|
1196
|
+
for (var proc of step.procs) {
|
|
1197
|
+
printWithIndent([translate("Parallel process") + " " + (proc.ordinal + 1)], indent2, output)
|
|
1198
|
+
printSteps(proc.body, depth + 2, output)
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
682
1201
|
|
|
683
1202
|
function printOther(step, indent, output) {
|
|
1203
|
+
var side = step.side
|
|
684
1204
|
if (!step.content && !step.secondary) {return}
|
|
685
1205
|
if (step.secondary) {
|
|
686
|
-
printStructuredContent(step.secondary, indent, output)
|
|
1206
|
+
printStructuredContent(step.secondary, indent, output, side)
|
|
1207
|
+
side = undefined
|
|
687
1208
|
}
|
|
688
1209
|
if (step.content) {
|
|
689
|
-
|
|
1210
|
+
var content = step.content
|
|
1211
|
+
if (step.type === "pause") {
|
|
1212
|
+
content = translate("Pause") + " " + htmlToString(content).join(" ")
|
|
1213
|
+
} else if (step.type === "timer") {
|
|
1214
|
+
content = translate("Start timer") + " " + htmlToString(content).join(" ")
|
|
1215
|
+
}
|
|
1216
|
+
printStructuredContent(content, indent, output, side)
|
|
690
1217
|
}
|
|
691
1218
|
}
|
|
692
1219
|
|
|
@@ -727,6 +1254,9 @@ function printPseudo(algorithm, translate, output, htmlToString) {
|
|
|
727
1254
|
var content = step.content
|
|
728
1255
|
var lines = printStructuredContentNoIdent(content)
|
|
729
1256
|
lines[0] = translate("if") + " " + lines[0]
|
|
1257
|
+
if (step.side) {
|
|
1258
|
+
lines[0] = step.side + ": " + lines[0]
|
|
1259
|
+
}
|
|
730
1260
|
printWithIndent(lines, indent, output)
|
|
731
1261
|
addRange(output, yesBody)
|
|
732
1262
|
if (!empty(noBody)) {
|
|
@@ -755,392 +1285,440 @@ function printPseudo(algorithm, translate, output, htmlToString) {
|
|
|
755
1285
|
}
|
|
756
1286
|
|
|
757
1287
|
module.exports = {printPseudo, printWithIndent, makeIndent}
|
|
758
|
-
},{"./tools":
|
|
759
|
-
var {buildTree} = require("./technicalTree")
|
|
1288
|
+
},{"./tools":10}],8:[function(require,module,exports){
|
|
1289
|
+
var { buildTree } = require("./technicalTree");
|
|
760
1290
|
const { createError, sortByProperty } = require("./tools");
|
|
761
|
-
const { optimizeTree } = require("./treeTools")
|
|
1291
|
+
const { optimizeTree } = require("./treeTools");
|
|
1292
|
+
const { flow_no_loop } = require("./noloop")
|
|
762
1293
|
|
|
763
1294
|
function redirectNode(nodes, node, from, to) {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
1295
|
+
if (node.one === from) {
|
|
1296
|
+
node.one = to;
|
|
1297
|
+
}
|
|
1298
|
+
if (node.two === from) {
|
|
1299
|
+
node.two = to;
|
|
1300
|
+
}
|
|
1301
|
+
if (node.next === from) {
|
|
1302
|
+
node.next = to;
|
|
1303
|
+
}
|
|
1304
|
+
if (node.start && node.type === "loopend") {
|
|
1305
|
+
start = nodes[node.start];
|
|
1306
|
+
if (start.next === from) {
|
|
1307
|
+
start.next = to;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
779
1310
|
}
|
|
780
1311
|
|
|
781
|
-
function structFlow(nodes, branches, filename, translate) {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
1312
|
+
function structFlow(nodes, branches, filename, translate, options) {
|
|
1313
|
+
function flowGraph(nodes, nodeId, branchingStack) {
|
|
1314
|
+
if (!nodeId) {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
const node = nodes[nodeId];
|
|
1319
|
+
|
|
1320
|
+
if (!node.stack) {
|
|
1321
|
+
node.stack = [];
|
|
1322
|
+
node.remaining = node.prev.length;
|
|
1323
|
+
}
|
|
1324
|
+
node.remaining--;
|
|
1325
|
+
|
|
1326
|
+
mergeBranchingStack(nodes, node, branchingStack);
|
|
1327
|
+
if (node.remaining > 0) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
if (node.type === "question") {
|
|
1332
|
+
for (let i = 0; i < node.stack.length; i++) {
|
|
1333
|
+
const questionId = node.stack[i];
|
|
1334
|
+
const question = nodes[questionId];
|
|
1335
|
+
question.branching++;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
const stackOne = node.stack.slice();
|
|
1339
|
+
const stackTwo = node.stack.slice();
|
|
1340
|
+
stackOne.push(nodeId);
|
|
1341
|
+
stackTwo.push(nodeId);
|
|
1342
|
+
|
|
1343
|
+
flowGraph(nodes, node.two, stackTwo);
|
|
1344
|
+
flowGraph(nodes, node.one, stackOne);
|
|
1345
|
+
} else if (node.type === "arrow-loop") {
|
|
1346
|
+
const stackOne = node.stack.slice();
|
|
1347
|
+
stackOne.push(nodeId);
|
|
1348
|
+
flowGraph(nodes, node.one, stackOne);
|
|
1349
|
+
} else if (node.type === "arrow-stub") {
|
|
1350
|
+
decrementBranchingForArrow(nodes, node);
|
|
1351
|
+
} else if (node.type === "parbegin") {
|
|
1352
|
+
for (var proc of node.procs) {
|
|
1353
|
+
flowGraph(nodes, proc.start, []);
|
|
1354
|
+
}
|
|
1355
|
+
flowGraph(nodes, node.one, node.stack);
|
|
1356
|
+
} else {
|
|
1357
|
+
flowGraph(nodes, node.one, node.stack);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
function decrementBranchingForArrow(nodes, node) {
|
|
1362
|
+
var algonode = nodes[node.arrow];
|
|
1363
|
+
algonode.branching--;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
function decrementQuestions(nodes, algonode, dictionary) {
|
|
1367
|
+
var stub = nodes[algonode.stub];
|
|
1368
|
+
for (var id of stub.stack) {
|
|
1369
|
+
var snode = nodes[id];
|
|
1370
|
+
if (id !== algonode.id) {
|
|
1371
|
+
if (id in dictionary) {
|
|
1372
|
+
snode.branching--;
|
|
793
1373
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
return stub;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
function mergeBranchingStack(nodes, node, branchingStack) {
|
|
1380
|
+
// Append all elements of the branching stack to node.stack
|
|
1381
|
+
addRange(node.stack, branchingStack);
|
|
1382
|
+
|
|
1383
|
+
// Build a dictionary of occurrences
|
|
1384
|
+
const dictionary = buildDictionaryOfOccurences(node);
|
|
1385
|
+
|
|
1386
|
+
// Merge all nodes
|
|
1387
|
+
mergeAll(nodes, node, dictionary);
|
|
1388
|
+
|
|
1389
|
+
// Rebuild the stack
|
|
1390
|
+
node.stack = buildStackFromDictionary(dictionary);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
function addRange(dst, src) {
|
|
1394
|
+
for (let i = 0; i < src.length; i++) {
|
|
1395
|
+
dst.push(src[i]);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
function buildStackFromDictionary(dictionary) {
|
|
1400
|
+
const rebuiltStack = [];
|
|
1401
|
+
for (const id in dictionary) {
|
|
1402
|
+
if (dictionary[id] > 0) {
|
|
1403
|
+
rebuiltStack.push(id);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
return rebuiltStack;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
function buildDictionaryOfOccurences(node) {
|
|
1410
|
+
const dictionary = {};
|
|
1411
|
+
for (let i = 0; i < node.stack.length; i++) {
|
|
1412
|
+
const id = node.stack[i];
|
|
1413
|
+
dictionary[id] = (dictionary[id] || 0) + 1;
|
|
1414
|
+
}
|
|
1415
|
+
return dictionary;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function mergeAll(nodes, node, dictionary) {
|
|
1419
|
+
for (const id in dictionary) {
|
|
1420
|
+
const occurrences = dictionary[id];
|
|
1421
|
+
const algonode = nodes[id];
|
|
1422
|
+
if (occurrences > 1) {
|
|
1423
|
+
algonode.branching--;
|
|
1424
|
+
dictionary[id] = occurrences - 1;
|
|
1425
|
+
}
|
|
1426
|
+
if (algonode.branching === 1) {
|
|
1427
|
+
if (algonode.type === "arrow-loop" && !algonode.next) {
|
|
1428
|
+
if (!isInMap(node.astack, id)) {
|
|
1429
|
+
algonode.next = node.id;
|
|
1430
|
+
dictionary[algonode.id] = 0;
|
|
1431
|
+
var stub = decrementQuestions(nodes, algonode, dictionary);
|
|
1432
|
+
stub.one = node.id;
|
|
1433
|
+
}
|
|
821
1434
|
}
|
|
1435
|
+
}
|
|
822
1436
|
}
|
|
823
1437
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
var stub = nodes[algonode.stub]
|
|
831
|
-
for (var id of stub.stack) {
|
|
832
|
-
var snode = nodes[id]
|
|
833
|
-
if (id != algonode) {
|
|
834
|
-
if (id in dictionary) {
|
|
835
|
-
snode.branching--
|
|
836
|
-
}
|
|
837
|
-
}
|
|
1438
|
+
for (const id in dictionary) {
|
|
1439
|
+
const algonode = nodes[id];
|
|
1440
|
+
if (algonode.branching === 1) {
|
|
1441
|
+
if (algonode.type === "question") {
|
|
1442
|
+
algonode.next = node.id;
|
|
1443
|
+
dictionary[algonode.id] = 0;
|
|
838
1444
|
}
|
|
839
|
-
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
node.
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
function isInMap(map, key) {
|
|
1449
|
+
if (!map) {
|
|
1450
|
+
return false;
|
|
1451
|
+
}
|
|
1452
|
+
return key in map;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
function prepareQuestions(nodes) {
|
|
1456
|
+
for (const nodeId in nodes) {
|
|
1457
|
+
const node = nodes[nodeId];
|
|
1458
|
+
if (node.type === "question") {
|
|
1459
|
+
node.branching = 2;
|
|
1460
|
+
} else if (node.type === "arrow-loop") {
|
|
1461
|
+
node.branching = 1;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
function rewireArrows(nodes, branches) {
|
|
1467
|
+
branches.forEach((branch) =>
|
|
1468
|
+
rewireArrowsInBranch(nodes, branch.id, branch.next, []),
|
|
1469
|
+
);
|
|
1470
|
+
for (var id in nodes) {
|
|
1471
|
+
var node = nodes[id];
|
|
1472
|
+
if (node.type === "arrow-loop") {
|
|
1473
|
+
var stub = insertArrowStub(nodes, node);
|
|
1474
|
+
var visited = {};
|
|
1475
|
+
fillAStack(nodes, stub, stub.arrow, visited);
|
|
1476
|
+
}
|
|
856
1477
|
}
|
|
1478
|
+
}
|
|
857
1479
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
}
|
|
1480
|
+
function fillAStack(nodes, node, arrowId, visited) {
|
|
1481
|
+
if (node.id in visited) {
|
|
1482
|
+
return;
|
|
862
1483
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
for (const id in dictionary) {
|
|
867
|
-
if (dictionary[id] > 0) {
|
|
868
|
-
rebuiltStack.push(id);
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
return rebuiltStack;
|
|
1484
|
+
visited[node.id] = true;
|
|
1485
|
+
if (!node.astack) {
|
|
1486
|
+
node.astack = {};
|
|
872
1487
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
for (let i = 0; i < node.stack.length; i++) {
|
|
877
|
-
const id = node.stack[i];
|
|
878
|
-
dictionary[id] = (dictionary[id] || 0) + 1;
|
|
879
|
-
}
|
|
880
|
-
return dictionary;
|
|
1488
|
+
node.astack[arrowId] = true;
|
|
1489
|
+
if (node.id === arrowId) {
|
|
1490
|
+
return;
|
|
881
1491
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
const occurrences = dictionary[id];
|
|
886
|
-
const algonode = nodes[id];
|
|
887
|
-
if (occurrences > 1) {
|
|
888
|
-
algonode.branching--;
|
|
889
|
-
dictionary[id] = occurrences - 1;
|
|
890
|
-
}
|
|
891
|
-
if (algonode.branching === 1) {
|
|
892
|
-
if (algonode.type === "arrow-loop" && !algonode.next) {
|
|
893
|
-
if (!isInMap(node.astack, id)) {
|
|
894
|
-
algonode.next = node.id
|
|
895
|
-
dictionary[algonode.id] = 0;
|
|
896
|
-
var stub = decrementQuestions(nodes, algonode, dictionary)
|
|
897
|
-
stub.one = node.id
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
for (const id in dictionary) {
|
|
904
|
-
const algonode = nodes[id];
|
|
905
|
-
if (algonode.branching === 1) {
|
|
906
|
-
if (algonode.type === "question") {
|
|
907
|
-
algonode.next = node.id;
|
|
908
|
-
dictionary[algonode.id] = 0;
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
function isInMap(map, key) {
|
|
914
|
-
if (!map) { return false }
|
|
915
|
-
return key in map
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
function prepareQuestions(nodes) {
|
|
919
|
-
for (const nodeId in nodes) {
|
|
920
|
-
const node = nodes[nodeId];
|
|
921
|
-
if (node.type === "question") {
|
|
922
|
-
node.branching = 2;
|
|
923
|
-
} else if (node.type === "arrow-loop") {
|
|
924
|
-
node.branching = 1;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
1492
|
+
for (var prevId of node.prev) {
|
|
1493
|
+
var prev = nodes[prevId];
|
|
1494
|
+
fillAStack(nodes, prev, arrowId, visited);
|
|
927
1495
|
}
|
|
1496
|
+
}
|
|
928
1497
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1498
|
+
function rewireArrowsInBranch(nodes, prevNodeId, nodeId, arrowStack) {
|
|
1499
|
+
if (!nodeId) {
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
var node = nodes[nodeId];
|
|
1503
|
+
if (node.type === "branch") {
|
|
1504
|
+
return;
|
|
1505
|
+
}
|
|
1506
|
+
if (node.type === "arrow-loop") {
|
|
1507
|
+
if (!node.noloop) {
|
|
1508
|
+
node.noloop = {};
|
|
1509
|
+
}
|
|
1510
|
+
if (arrowStack.includes(nodeId)) {
|
|
1511
|
+
return;
|
|
1512
|
+
}
|
|
1513
|
+
node.noloop[prevNodeId] = true;
|
|
1514
|
+
arrowStack = arrowStack.slice();
|
|
1515
|
+
arrowStack.push(nodeId);
|
|
1516
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack);
|
|
1517
|
+
} else if (node.type === "question") {
|
|
1518
|
+
var left = arrowStack.slice();
|
|
1519
|
+
var right = arrowStack.slice();
|
|
1520
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, left);
|
|
1521
|
+
rewireArrowsInBranch(nodes, nodeId, node.two, right);
|
|
1522
|
+
} else if (node.type === "parbegin") {
|
|
1523
|
+
for (var proc of node.procs) {
|
|
1524
|
+
rewireArrowsInBranch(nodes, undefined, proc.start, []);
|
|
1525
|
+
}
|
|
1526
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack);
|
|
1527
|
+
} else {
|
|
1528
|
+
rewireArrowsInBranch(nodes, nodeId, node.one, arrowStack);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
function insertArrowStub(nodes, node) {
|
|
1533
|
+
var stub = {
|
|
1534
|
+
type: "arrow-stub",
|
|
1535
|
+
id: "arrow-stub-" + node.id,
|
|
1536
|
+
arrow: node.id,
|
|
1537
|
+
prev: [],
|
|
1538
|
+
};
|
|
1539
|
+
nodes[stub.id] = stub;
|
|
1540
|
+
node.stub = stub.id;
|
|
1541
|
+
var prev2 = [];
|
|
1542
|
+
for (var prevId of node.prev) {
|
|
1543
|
+
if (prevId in node.noloop) {
|
|
1544
|
+
prev2.push(prevId);
|
|
1545
|
+
} else {
|
|
1546
|
+
stub.prev.push(prevId);
|
|
1547
|
+
var prev = nodes[prevId];
|
|
1548
|
+
redirectNode(nodes, prev, node.id, stub.id);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
node.prev = prev2;
|
|
1552
|
+
return stub;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
function copySide(dst, src) {
|
|
1556
|
+
if (src.side) {
|
|
1557
|
+
dst.side = src.side;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
function rewriteTree(body, index, endId, output) {
|
|
1562
|
+
while (index < body.length) {
|
|
1563
|
+
var node = body[index];
|
|
1564
|
+
index++;
|
|
1565
|
+
if (endId && node.id === endId) {
|
|
1566
|
+
return index;
|
|
1567
|
+
}
|
|
1568
|
+
if (node.type === "question") {
|
|
1569
|
+
var transformed = rewriteQuestionTree(node, output);
|
|
1570
|
+
copySide(transformed, node);
|
|
1571
|
+
if (endId) {
|
|
1572
|
+
var breakYes = findLoopEnd(transformed.yes, endId);
|
|
1573
|
+
var breakNo = findLoopEnd(transformed.no, endId);
|
|
1574
|
+
if (breakYes || breakNo) {
|
|
1575
|
+
var toBreak = [];
|
|
1576
|
+
findPlacesToBreak(transformed.yes, endId, toBreak);
|
|
1577
|
+
findPlacesToBreak(transformed.no, endId, toBreak);
|
|
1578
|
+
addBreaks(toBreak);
|
|
1579
|
+
return index;
|
|
1580
|
+
}
|
|
978
1581
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
return stub
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
function rewriteTree(body, index, endId, output) {
|
|
1005
|
-
while (index < body.length) {
|
|
1006
|
-
var node = body[index]
|
|
1007
|
-
index++
|
|
1008
|
-
if (endId && node.id === endId) {
|
|
1009
|
-
return index
|
|
1010
|
-
}
|
|
1011
|
-
if (node.type === "question") {
|
|
1012
|
-
var transformed = rewriteQuestionTree(node, output)
|
|
1013
|
-
if (endId) {
|
|
1014
|
-
var breakYes = findLoopEnd(transformed.yes, endId)
|
|
1015
|
-
var breakNo = findLoopEnd(transformed.no, endId)
|
|
1016
|
-
if (breakYes || breakNo) {
|
|
1017
|
-
var toBreak = []
|
|
1018
|
-
findPlacesToBreak(transformed.yes, endId, toBreak)
|
|
1019
|
-
findPlacesToBreak(transformed.no, endId, toBreak)
|
|
1020
|
-
addBreaks(toBreak)
|
|
1021
|
-
return index
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
} else if (node.type === "loopbegin") {
|
|
1025
|
-
var body2 = []
|
|
1026
|
-
index = rewriteTree(body, index, node.end, body2)
|
|
1027
|
-
output.push({
|
|
1028
|
-
id: node.id,
|
|
1029
|
-
type: "loop",
|
|
1030
|
-
content: node.content,
|
|
1031
|
-
body: body2
|
|
1032
|
-
})
|
|
1033
|
-
} else {
|
|
1034
|
-
output.push(node)
|
|
1035
|
-
}
|
|
1582
|
+
} else if (node.type === "loopbegin") {
|
|
1583
|
+
var body2 = [];
|
|
1584
|
+
index = rewriteTree(body, index, node.end, body2);
|
|
1585
|
+
output.push({
|
|
1586
|
+
id: node.id,
|
|
1587
|
+
type: "loop",
|
|
1588
|
+
content: node.content,
|
|
1589
|
+
body: body2,
|
|
1590
|
+
});
|
|
1591
|
+
} else if (node.type === "parbegin") {
|
|
1592
|
+
var copy = {
|
|
1593
|
+
id: node.id,
|
|
1594
|
+
type: node.type,
|
|
1595
|
+
procs: [],
|
|
1596
|
+
};
|
|
1597
|
+
for (var proc of node.procs) {
|
|
1598
|
+
var procCopy = {
|
|
1599
|
+
ordinal: proc.ordinal,
|
|
1600
|
+
body: [],
|
|
1601
|
+
};
|
|
1602
|
+
copy.procs.push(procCopy);
|
|
1603
|
+
rewriteTree(proc.body, 0, undefined, procCopy.body);
|
|
1036
1604
|
}
|
|
1605
|
+
output.push(copy);
|
|
1606
|
+
} else {
|
|
1607
|
+
output.push(node);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
function findPlacesToBreak(body, endId, output) {
|
|
1613
|
+
if (body.length === 0) {
|
|
1614
|
+
output.push(body);
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
var last = body[body.length - 1];
|
|
1618
|
+
if (last.id === endId) {
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
if (last.type === "question") {
|
|
1622
|
+
var qends = [];
|
|
1623
|
+
findPlacesToBreak(last.yes, endId, qends);
|
|
1624
|
+
findPlacesToBreak(last.no, endId, qends);
|
|
1625
|
+
if (qends.length === 2 && qends[0] === last.yes && qends[1] === last.no) {
|
|
1626
|
+
output.push(body);
|
|
1627
|
+
} else {
|
|
1628
|
+
addRange(output, qends);
|
|
1629
|
+
}
|
|
1630
|
+
} else {
|
|
1631
|
+
output.push(body);
|
|
1037
1632
|
}
|
|
1633
|
+
}
|
|
1038
1634
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
if (last.id === endId) {
|
|
1046
|
-
return
|
|
1047
|
-
}
|
|
1048
|
-
if (last.type === "question") {
|
|
1049
|
-
var qends = []
|
|
1050
|
-
findPlacesToBreak(last.yes, endId, qends)
|
|
1051
|
-
findPlacesToBreak(last.no, endId, qends)
|
|
1052
|
-
if (qends.length === 2
|
|
1053
|
-
&& qends[0] === last.yes
|
|
1054
|
-
&& qends[1] === last.no) {
|
|
1055
|
-
output.push(body)
|
|
1056
|
-
} else {
|
|
1057
|
-
addRange(output, qends)
|
|
1058
|
-
}
|
|
1635
|
+
function findLoopEnd(body, endId) {
|
|
1636
|
+
for (var i = 0; i < body.length; i++) {
|
|
1637
|
+
var node = body[i];
|
|
1638
|
+
if (node.id === endId) {
|
|
1639
|
+
if (i === body.length - 1) {
|
|
1640
|
+
return true;
|
|
1059
1641
|
} else {
|
|
1060
|
-
|
|
1642
|
+
throw createError(
|
|
1643
|
+
translate(
|
|
1644
|
+
"An exit from the loop must lead to the point right after the loop end",
|
|
1645
|
+
),
|
|
1646
|
+
filename,
|
|
1647
|
+
node.id,
|
|
1648
|
+
);
|
|
1061
1649
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
var node = body[i]
|
|
1067
|
-
if (node.id === endId) {
|
|
1068
|
-
if (i === body.length - 1) {
|
|
1069
|
-
return true
|
|
1070
|
-
} else {
|
|
1071
|
-
throw createError(
|
|
1072
|
-
translate("An exit from the loop must lead to the point right after the loop end"),
|
|
1073
|
-
filename,
|
|
1074
|
-
node.id
|
|
1075
|
-
);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
if (node.type === "question") {
|
|
1079
|
-
if (findLoopEnd(node.yes, endId)) {
|
|
1080
|
-
return true
|
|
1081
|
-
}
|
|
1082
|
-
if (findLoopEnd(node.no, endId)) {
|
|
1083
|
-
return true
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1650
|
+
}
|
|
1651
|
+
if (node.type === "question") {
|
|
1652
|
+
if (findLoopEnd(node.yes, endId)) {
|
|
1653
|
+
return true;
|
|
1086
1654
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
function addBreaks(toBreak) {
|
|
1091
|
-
for (var body of toBreak) {
|
|
1092
|
-
body.push({
|
|
1093
|
-
type: "break"
|
|
1094
|
-
})
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
function rewriteQuestionTree(question, output) {
|
|
1099
|
-
var yes = []
|
|
1100
|
-
var no = []
|
|
1101
|
-
rewriteTree(question.yes, 0, undefined, yes)
|
|
1102
|
-
rewriteTree(question.no, 0, undefined, no)
|
|
1103
|
-
var transformed = {
|
|
1104
|
-
type: "question",
|
|
1105
|
-
id: question.id,
|
|
1106
|
-
content: question.content,
|
|
1107
|
-
yes: yes,
|
|
1108
|
-
no: no
|
|
1655
|
+
if (findLoopEnd(node.no, endId)) {
|
|
1656
|
+
return true;
|
|
1109
1657
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return false;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
function addBreaks(toBreak) {
|
|
1664
|
+
for (var body of toBreak) {
|
|
1665
|
+
body.push({
|
|
1666
|
+
type: "break",
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
function rewriteQuestionTree(question, output) {
|
|
1672
|
+
var yes = [];
|
|
1673
|
+
var no = [];
|
|
1674
|
+
rewriteTree(question.yes, 0, undefined, yes);
|
|
1675
|
+
rewriteTree(question.no, 0, undefined, no);
|
|
1676
|
+
var transformed = {
|
|
1677
|
+
type: "question",
|
|
1678
|
+
id: question.id,
|
|
1679
|
+
content: question.content,
|
|
1680
|
+
yes: yes,
|
|
1681
|
+
no: no,
|
|
1682
|
+
};
|
|
1683
|
+
output.push(transformed);
|
|
1684
|
+
return transformed;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
function structMain() {
|
|
1688
|
+
rewireArrows(nodes, branches);
|
|
1689
|
+
prepareQuestions(nodes);
|
|
1690
|
+
var result = [];
|
|
1691
|
+
|
|
1692
|
+
for (var branch of branches) {
|
|
1693
|
+
if (options.noLoop) {
|
|
1694
|
+
flow_no_loop(nodes, branch.next, []);
|
|
1695
|
+
} else {
|
|
1696
|
+
flowGraph(nodes, branch.next, []);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
for (var branch of branches) {
|
|
1701
|
+
var body = [];
|
|
1702
|
+
buildTree(nodes, branch.next, body, "<dummy id>");
|
|
1703
|
+
var body2 = [];
|
|
1704
|
+
rewriteTree(body, 0, undefined, body2);
|
|
1705
|
+
result.push({
|
|
1706
|
+
name: branch.content,
|
|
1707
|
+
branchId: branch.branchId,
|
|
1708
|
+
start: branch.next,
|
|
1709
|
+
refs: branch.prev.length,
|
|
1710
|
+
body: optimizeTree(body2),
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
return sortByProperty(result, "branchId");
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
return structMain();
|
|
1141
1718
|
}
|
|
1142
1719
|
module.exports = { structFlow, redirectNode };
|
|
1143
|
-
|
|
1720
|
+
|
|
1721
|
+
},{"./noloop":6,"./technicalTree":9,"./tools":10,"./treeTools":12}],9:[function(require,module,exports){
|
|
1144
1722
|
function buildTree(nodes, nodeId, body, stopId) {
|
|
1145
1723
|
while (nodeId) {
|
|
1146
1724
|
if (nodeId === stopId) {return;}
|
|
@@ -1180,6 +1758,21 @@ function buildTree(nodes, nodeId, body, stopId) {
|
|
|
1180
1758
|
start: node.arrow
|
|
1181
1759
|
};
|
|
1182
1760
|
|
|
1761
|
+
next = node.one;
|
|
1762
|
+
} else if (node.type === "parbegin") {
|
|
1763
|
+
transformed = {
|
|
1764
|
+
id: node.id,
|
|
1765
|
+
type: node.type,
|
|
1766
|
+
procs: []
|
|
1767
|
+
}
|
|
1768
|
+
for (var proc of node.procs) {
|
|
1769
|
+
var childProc = {
|
|
1770
|
+
ordinal: proc.ordinal,
|
|
1771
|
+
body: []
|
|
1772
|
+
}
|
|
1773
|
+
transformed.procs.push(childProc)
|
|
1774
|
+
buildTree(nodes, proc.start, childProc.body, undefined)
|
|
1775
|
+
}
|
|
1183
1776
|
next = node.one;
|
|
1184
1777
|
} else {
|
|
1185
1778
|
transformed = {
|
|
@@ -1198,8 +1791,13 @@ function buildTree(nodes, nodeId, body, stopId) {
|
|
|
1198
1791
|
]
|
|
1199
1792
|
)
|
|
1200
1793
|
next = node.one;
|
|
1794
|
+
if (node.final) {
|
|
1795
|
+
next = undefined
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
if (node.side) {
|
|
1799
|
+
transformed.side = node.side
|
|
1201
1800
|
}
|
|
1202
|
-
|
|
1203
1801
|
body.push(transformed);
|
|
1204
1802
|
nodeId = next;
|
|
1205
1803
|
}
|
|
@@ -1215,6 +1813,9 @@ function copyFields(dst, src, fields) {
|
|
|
1215
1813
|
}
|
|
1216
1814
|
|
|
1217
1815
|
function reserveNext(nodes, node) {
|
|
1816
|
+
if (!node.next) {
|
|
1817
|
+
return undefined
|
|
1818
|
+
}
|
|
1218
1819
|
const target = nodes[node.next];
|
|
1219
1820
|
if (target.targetTaken) {
|
|
1220
1821
|
return undefined;
|
|
@@ -1226,7 +1827,7 @@ function reserveNext(nodes, node) {
|
|
|
1226
1827
|
|
|
1227
1828
|
module.exports = {buildTree}
|
|
1228
1829
|
|
|
1229
|
-
},{}],
|
|
1830
|
+
},{}],10:[function(require,module,exports){
|
|
1230
1831
|
|
|
1231
1832
|
function createError(message, filename, nodeId) {
|
|
1232
1833
|
var error = new Error(message)
|
|
@@ -1267,7 +1868,7 @@ function addRange(to, from) {
|
|
|
1267
1868
|
}
|
|
1268
1869
|
}
|
|
1269
1870
|
module.exports = { createError, sortByProperty, addRange, remove }
|
|
1270
|
-
},{}],
|
|
1871
|
+
},{}],11:[function(require,module,exports){
|
|
1271
1872
|
var translationsRu = {
|
|
1272
1873
|
"error": "ОШИБКА",
|
|
1273
1874
|
"not": "не",
|
|
@@ -1296,7 +1897,13 @@ var translationsRu = {
|
|
|
1296
1897
|
"Description": "Описание",
|
|
1297
1898
|
"Algorithm": "Алгоритм",
|
|
1298
1899
|
Remarks: "Замечания",
|
|
1299
|
-
Parameters: "Параметры"
|
|
1900
|
+
Parameters: "Параметры",
|
|
1901
|
+
"Group of parallel processes": "Группа параллельных процессов",
|
|
1902
|
+
"Parallel process": "Параллельный процесс",
|
|
1903
|
+
"Start at": "Начать в",
|
|
1904
|
+
"Do for": "Делать в течение",
|
|
1905
|
+
"Pause": "Пауза",
|
|
1906
|
+
"Start timer": "Запустить таймер"
|
|
1300
1907
|
}
|
|
1301
1908
|
|
|
1302
1909
|
var translationsEn = {
|
|
@@ -1327,7 +1934,13 @@ var translationsEn = {
|
|
|
1327
1934
|
Description: 'Description',
|
|
1328
1935
|
Algorithm: 'Algorithm',
|
|
1329
1936
|
Remarks: "Remarks",
|
|
1330
|
-
Parameters: "Parameters"
|
|
1937
|
+
Parameters: "Parameters",
|
|
1938
|
+
"Group of parallel processes": "Group of parallel processes",
|
|
1939
|
+
"Parallel process": "Parallel process",
|
|
1940
|
+
"Start at": "Start at",
|
|
1941
|
+
"Do for": "Do for",
|
|
1942
|
+
"Pause": "Pause",
|
|
1943
|
+
"Start timer": "Start timer",
|
|
1331
1944
|
}
|
|
1332
1945
|
|
|
1333
1946
|
var translationsNo = {
|
|
@@ -1358,7 +1971,13 @@ var translationsNo = {
|
|
|
1358
1971
|
Description: 'Beskrivelse',
|
|
1359
1972
|
Algorithm: 'Algoritme',
|
|
1360
1973
|
Remarks: "Bemerkninger",
|
|
1361
|
-
Parameters: "Parametere"
|
|
1974
|
+
Parameters: "Parametere",
|
|
1975
|
+
"Group of parallel processes": "Gruppe av parallelle prosesser",
|
|
1976
|
+
"Parallel process": "Parallell prosess",
|
|
1977
|
+
"Start at": "Start ved",
|
|
1978
|
+
"Do for": "Gjør i",
|
|
1979
|
+
"Pause": "Pause",
|
|
1980
|
+
"Start timer": "Start tidtaker"
|
|
1362
1981
|
};
|
|
1363
1982
|
|
|
1364
1983
|
|
|
@@ -1382,7 +2001,7 @@ function setUpLanguage(language) {
|
|
|
1382
2001
|
|
|
1383
2002
|
|
|
1384
2003
|
module.exports = { setUpLanguage, translate };
|
|
1385
|
-
},{}],
|
|
2004
|
+
},{}],12:[function(require,module,exports){
|
|
1386
2005
|
|
|
1387
2006
|
function optimizeTree(steps) {
|
|
1388
2007
|
var result = []
|
|
@@ -1393,6 +2012,8 @@ function optimizeTree(steps) {
|
|
|
1393
2012
|
var copy
|
|
1394
2013
|
if (step.type === "question") {
|
|
1395
2014
|
copy = optimizeQuestion(step)
|
|
2015
|
+
} else if (step.type === "parbegin") {
|
|
2016
|
+
copy = optimizeParbegin(step)
|
|
1396
2017
|
} else if (step.type === "loop") {
|
|
1397
2018
|
copy = optimizeLoop(step)
|
|
1398
2019
|
} else {
|
|
@@ -1404,6 +2025,22 @@ function optimizeTree(steps) {
|
|
|
1404
2025
|
return result
|
|
1405
2026
|
}
|
|
1406
2027
|
|
|
2028
|
+
function optimizeParbegin(step) {
|
|
2029
|
+
var procs = []
|
|
2030
|
+
for (var proc of step.procs) {
|
|
2031
|
+
var procCopy = {
|
|
2032
|
+
ordinal: proc.ordinal,
|
|
2033
|
+
body: optimizeTree(proc.body)
|
|
2034
|
+
}
|
|
2035
|
+
procs.push(procCopy)
|
|
2036
|
+
}
|
|
2037
|
+
return {
|
|
2038
|
+
id: step.id,
|
|
2039
|
+
type: step.type,
|
|
2040
|
+
procs: procs
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
|
|
1407
2044
|
function optimizeLoop(step) {
|
|
1408
2045
|
return {
|
|
1409
2046
|
id: step.id,
|
|
@@ -1418,6 +2055,7 @@ function optimizeQuestion(step) {
|
|
|
1418
2055
|
var no = optimizeTree(step.no)
|
|
1419
2056
|
if (yes.length === 0 && no.length === 0) {
|
|
1420
2057
|
return {
|
|
2058
|
+
side: step.side,
|
|
1421
2059
|
type: step.type,
|
|
1422
2060
|
content: step.content,
|
|
1423
2061
|
yes: [],
|
|
@@ -1426,6 +2064,7 @@ function optimizeQuestion(step) {
|
|
|
1426
2064
|
}
|
|
1427
2065
|
if (yes.length === 0) {
|
|
1428
2066
|
return {
|
|
2067
|
+
side: step.side,
|
|
1429
2068
|
type: step.type,
|
|
1430
2069
|
content: {operator:"not",operand:step.content},
|
|
1431
2070
|
yes: no,
|
|
@@ -1433,6 +2072,7 @@ function optimizeQuestion(step) {
|
|
|
1433
2072
|
}
|
|
1434
2073
|
}
|
|
1435
2074
|
return {
|
|
2075
|
+
side: step.side,
|
|
1436
2076
|
type: step.type,
|
|
1437
2077
|
content: step.content,
|
|
1438
2078
|
yes: yes,
|