@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("------------------------- MODULE UserApp -------------------------");
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 > 0) {
1366
- const exceptClauses = validAssignments.map((a) => {
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
- if (preconditions.length === 0) {
1374
- this.line("\\* No state changes in handler");
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: "SelectSeq(@, LAMBDA t: TRUE)" };
5022
+ return { field: signalName, value: "NDET:FILTER" };
4944
5023
  case "map":
4945
- return { field: signalName, value: "[i \\in DOMAIN @ |-> @[i]]" };
5024
+ return { field: signalName, value: "NDET:MAP" };
4946
5025
  case "slice":
4947
- return { field: signalName, value: "SubSeq(@, 1, Len(@))" };
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=7EE824400DEB8F7564756E2164756E21
7425
+ //# debugId=E5DA6950FD1E0C7764756E2164756E21