@fairfox/polly 0.18.0 → 0.19.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.
|
@@ -429,13 +429,22 @@ async function generateSubsystemTLA(_subsystemName, subsystem, config, analysis)
|
|
|
429
429
|
temporalConstraints: filteredConfig.tier2.temporalConstraints.filter((tc) => handlerNames.has(tc.before) && handlerNames.has(tc.after))
|
|
430
430
|
};
|
|
431
431
|
}
|
|
432
|
+
const subsystemFieldPatterns = subsystem.state.map((field) => {
|
|
433
|
+
const dotIdx = field.indexOf(".");
|
|
434
|
+
if (dotIdx >= 0) {
|
|
435
|
+
return `${field.substring(0, dotIdx)}.value.${field.substring(dotIdx + 1)}`;
|
|
436
|
+
}
|
|
437
|
+
return `${field}.value`;
|
|
438
|
+
});
|
|
439
|
+
const filteredGlobalStateConstraints = (analysis.globalStateConstraints ?? []).filter((constraint) => subsystemFieldPatterns.some((pattern) => constraint.expression.includes(pattern)));
|
|
432
440
|
const filteredAnalysis = {
|
|
433
441
|
...analysis,
|
|
434
442
|
messageTypes: analysis.messageTypes.filter((mt) => handlerNames.has(mt)),
|
|
435
|
-
handlers: analysis.handlers.filter((h) => handlerNames.has(h.messageType))
|
|
443
|
+
handlers: analysis.handlers.filter((h) => handlerNames.has(h.messageType)),
|
|
444
|
+
globalStateConstraints: filteredGlobalStateConstraints
|
|
436
445
|
};
|
|
437
446
|
const generator = new TLAGenerator;
|
|
438
|
-
return await generator.generate(filteredConfig, filteredAnalysis);
|
|
447
|
+
return await generator.generate(filteredConfig, filteredAnalysis, `UserApp_${_subsystemName}`);
|
|
439
448
|
}
|
|
440
449
|
var TLAValidationError, TLAGenerator;
|
|
441
450
|
var init_tla = __esm(() => {
|
|
@@ -458,6 +467,7 @@ var init_tla = __esm(() => {
|
|
|
458
467
|
resolvedActionNames = new Map;
|
|
459
468
|
tabSymmetryEnabled = false;
|
|
460
469
|
tabCount = 0;
|
|
470
|
+
moduleName = "UserApp";
|
|
461
471
|
constructor(options) {
|
|
462
472
|
this.options = options;
|
|
463
473
|
}
|
|
@@ -467,7 +477,10 @@ var init_tla = __esm(() => {
|
|
|
467
477
|
}
|
|
468
478
|
return /^[a-zA-Z][a-zA-Z0-9_]*$/.test(s);
|
|
469
479
|
}
|
|
470
|
-
async generate(config, analysis) {
|
|
480
|
+
async generate(config, analysis, moduleName) {
|
|
481
|
+
if (moduleName) {
|
|
482
|
+
this.moduleName = moduleName;
|
|
483
|
+
}
|
|
471
484
|
this.validateInputs(config, analysis);
|
|
472
485
|
this.extractInvariantsIfEnabled();
|
|
473
486
|
this.generateTemporalPropertiesIfEnabled(analysis);
|
|
@@ -757,7 +770,7 @@ var init_tla = __esm(() => {
|
|
|
757
770
|
}
|
|
758
771
|
}
|
|
759
772
|
addHeader() {
|
|
760
|
-
this.line(
|
|
773
|
+
this.line(`------------------------- MODULE ${this.moduleName} -------------------------`);
|
|
761
774
|
this.line("(*");
|
|
762
775
|
this.line(" Auto-generated TLA+ specification for web extension");
|
|
763
776
|
this.line(" ");
|
|
@@ -1362,19 +1375,61 @@ var init_tla = __esm(() => {
|
|
|
1362
1375
|
return assignment;
|
|
1363
1376
|
}
|
|
1364
1377
|
emitStateUpdates(validAssignments, preconditions) {
|
|
1365
|
-
if (validAssignments.length
|
|
1366
|
-
|
|
1378
|
+
if (validAssignments.length === 0) {
|
|
1379
|
+
if (preconditions.length === 0) {
|
|
1380
|
+
this.line("\\* No state changes in handler");
|
|
1381
|
+
}
|
|
1382
|
+
this.line("/\\ UNCHANGED contextStates");
|
|
1383
|
+
return true;
|
|
1384
|
+
}
|
|
1385
|
+
const ndetAssignments = [];
|
|
1386
|
+
const detAssignments = [];
|
|
1387
|
+
for (const a of validAssignments) {
|
|
1388
|
+
if (typeof a.value === "string" && a.value.startsWith("NDET:")) {
|
|
1389
|
+
ndetAssignments.push({ field: a.field, value: a.value });
|
|
1390
|
+
} else {
|
|
1391
|
+
detAssignments.push(a);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
if (ndetAssignments.length === 0) {
|
|
1395
|
+
const exceptClauses = detAssignments.map((a) => {
|
|
1367
1396
|
const tlaValue = this.assignmentValueToTLA(a.value);
|
|
1368
1397
|
return `![ctx].${this.sanitizeFieldName(a.field)} = ${tlaValue}`;
|
|
1369
1398
|
});
|
|
1370
1399
|
this.line(`/\\ contextStates' = [contextStates EXCEPT ${exceptClauses.join(", ")}]`);
|
|
1371
1400
|
return false;
|
|
1372
1401
|
}
|
|
1373
|
-
|
|
1374
|
-
|
|
1402
|
+
this.emitNDETStateUpdates(ndetAssignments, detAssignments);
|
|
1403
|
+
return false;
|
|
1404
|
+
}
|
|
1405
|
+
emitNDETStateUpdates(ndetAssignments, detAssignments) {
|
|
1406
|
+
const detExceptClauses = detAssignments.map((a) => {
|
|
1407
|
+
const tlaValue = this.assignmentValueToTLA(a.value);
|
|
1408
|
+
return `![ctx].${this.sanitizeFieldName(a.field)} = ${tlaValue}`;
|
|
1409
|
+
});
|
|
1410
|
+
const ndetExceptClauses = [];
|
|
1411
|
+
const quantifierOpeners = [];
|
|
1412
|
+
for (const a of ndetAssignments) {
|
|
1413
|
+
const fieldName = this.sanitizeFieldName(a.field);
|
|
1414
|
+
const fieldRef = `contextStates[ctx].${fieldName}`;
|
|
1415
|
+
if (a.value === "NDET:FILTER") {
|
|
1416
|
+
quantifierOpeners.push(`/\\ \\E newLen_${fieldName} \\in 0..Len(${fieldRef}) :`);
|
|
1417
|
+
ndetExceptClauses.push(`![ctx].${fieldName} = SubSeq(@, 1, newLen_${fieldName})`);
|
|
1418
|
+
} else if (a.value === "NDET:MAP") {
|
|
1419
|
+
quantifierOpeners.push(`/\\ \\E mapIdx_${fieldName} \\in 1..Len(${fieldRef}) :`);
|
|
1420
|
+
quantifierOpeners.push(`\\E mapVal_${fieldName} \\in Value :`);
|
|
1421
|
+
ndetExceptClauses.push(`![ctx].${fieldName} = [@ EXCEPT ![mapIdx_${fieldName}] = mapVal_${fieldName}]`);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
for (const opener of quantifierOpeners) {
|
|
1425
|
+
this.line(opener);
|
|
1426
|
+
this.indent++;
|
|
1427
|
+
}
|
|
1428
|
+
const allExceptClauses = [...detExceptClauses, ...ndetExceptClauses];
|
|
1429
|
+
this.line(`/\\ contextStates' = [contextStates EXCEPT ${allExceptClauses.join(", ")}]`);
|
|
1430
|
+
for (const _opener of quantifierOpeners) {
|
|
1431
|
+
this.indent--;
|
|
1375
1432
|
}
|
|
1376
|
-
this.line("/\\ UNCHANGED contextStates");
|
|
1377
|
-
return true;
|
|
1378
1433
|
}
|
|
1379
1434
|
tsExpressionToTLA(expr, isPrimed = false) {
|
|
1380
1435
|
if (!expr || typeof expr !== "string") {
|
|
@@ -1787,6 +1842,9 @@ var init_tla = __esm(() => {
|
|
|
1787
1842
|
return "NULL";
|
|
1788
1843
|
}
|
|
1789
1844
|
if (typeof value === "string") {
|
|
1845
|
+
if (value.startsWith("NDET:")) {
|
|
1846
|
+
throw new Error(`NDET marker "${value}" reached assignmentValueToTLA — should have been partitioned in emitStateUpdates`);
|
|
1847
|
+
}
|
|
1790
1848
|
if (value.startsWith("param:")) {
|
|
1791
1849
|
const paramName = value.substring(6);
|
|
1792
1850
|
return `payload.${this.sanitizeFieldName(paramName)}`;
|
|
@@ -4705,7 +4763,9 @@ class HandlerExtractor {
|
|
|
4705
4763
|
return;
|
|
4706
4764
|
if (this.tryExtractSetConstructorPattern(fieldPath, right, assignments))
|
|
4707
4765
|
return;
|
|
4708
|
-
this.tryExtractMapConstructorPattern(fieldPath, right, assignments)
|
|
4766
|
+
if (this.tryExtractMapConstructorPattern(fieldPath, right, assignments))
|
|
4767
|
+
return;
|
|
4768
|
+
this.tryExtractSignalDirectValuePattern(fieldPath, right, assignments);
|
|
4709
4769
|
}
|
|
4710
4770
|
tryExtractStateFieldPattern(fieldPath, right, assignments) {
|
|
4711
4771
|
if (!fieldPath.startsWith("state."))
|
|
@@ -4824,6 +4884,25 @@ class HandlerExtractor {
|
|
|
4824
4884
|
}
|
|
4825
4885
|
return true;
|
|
4826
4886
|
}
|
|
4887
|
+
tryExtractSignalDirectValuePattern(fieldPath, right, assignments) {
|
|
4888
|
+
if (!fieldPath.endsWith(".value"))
|
|
4889
|
+
return false;
|
|
4890
|
+
const signalName = fieldPath.slice(0, -6);
|
|
4891
|
+
const literalValue = this.extractValue(right);
|
|
4892
|
+
if (literalValue !== undefined) {
|
|
4893
|
+
assignments.push({ field: signalName, value: literalValue });
|
|
4894
|
+
return true;
|
|
4895
|
+
}
|
|
4896
|
+
if (Node2.isPropertyAccessExpression(right)) {
|
|
4897
|
+
const rightPath = this.getPropertyPath(right);
|
|
4898
|
+
const parts = rightPath.split(".");
|
|
4899
|
+
if (parts.length === 2 && parts[0] !== undefined && parts[1] !== undefined && this.currentFunctionParams.includes(parts[0])) {
|
|
4900
|
+
assignments.push({ field: signalName, value: `param:${parts[1]}` });
|
|
4901
|
+
return true;
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
return false;
|
|
4905
|
+
}
|
|
4827
4906
|
extractSetOperation(newExpr, fieldPath, signalName) {
|
|
4828
4907
|
const args = newExpr.getArguments();
|
|
4829
4908
|
if (args.length === 0) {
|
|
@@ -4940,11 +5019,11 @@ class HandlerExtractor {
|
|
|
4940
5019
|
return null;
|
|
4941
5020
|
switch (methodName) {
|
|
4942
5021
|
case "filter":
|
|
4943
|
-
return { field: signalName, value: "
|
|
5022
|
+
return { field: signalName, value: "NDET:FILTER" };
|
|
4944
5023
|
case "map":
|
|
4945
|
-
return { field: signalName, value: "
|
|
5024
|
+
return { field: signalName, value: "NDET:MAP" };
|
|
4946
5025
|
case "slice":
|
|
4947
|
-
return { field: signalName, value: "
|
|
5026
|
+
return { field: signalName, value: "NDET:FILTER" };
|
|
4948
5027
|
case "concat":
|
|
4949
5028
|
return { field: signalName, value: "@ \\o <<payload>>" };
|
|
4950
5029
|
case "reverse":
|
|
@@ -7343,4 +7422,4 @@ main().catch((error) => {
|
|
|
7343
7422
|
process.exit(1);
|
|
7344
7423
|
});
|
|
7345
7424
|
|
|
7346
|
-
//# debugId=
|
|
7425
|
+
//# debugId=E5DA6950FD1E0C7764756E2164756E21
|