@fairfox/polly 0.34.0 → 0.35.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.
@@ -339,6 +339,9 @@ class TemporalTLAGenerator {
339
339
  case "always":
340
340
  lines.push(`${prop.name} == [](${prop.target})`);
341
341
  break;
342
+ case "step-always":
343
+ lines.push(`${prop.name} == [][${prop.target}]_allVars`);
344
+ break;
342
345
  case "until":
343
346
  if (prop.trigger) {
344
347
  lines.push(`${prop.name} == (${prop.trigger}) U (${prop.target})`);
@@ -651,6 +654,7 @@ var init_tla = __esm(() => {
651
654
  if (this.temporalProperties.length > 0) {
652
655
  this.addTemporalProperties();
653
656
  }
657
+ this.line("=============================================================================");
654
658
  return this.lines.join(`
655
659
  `);
656
660
  }
@@ -708,7 +712,7 @@ var init_tla = __esm(() => {
708
712
  }
709
713
  const tabValues = Array.from({ length: this.tabCount }, (_, i) => `Tab${i}`).join(", ");
710
714
  lines.push(` Tabs = {${tabValues}}`);
711
- } else if ("maxTabs" in messages && messages.maxTabs !== undefined) {
715
+ } else if ("maxTabs" in messages && messages.maxTabs !== undefined && messages.maxTabs !== null) {
712
716
  const tabValues = Array.from({ length: messages.maxTabs + 1 }, (_, i) => i).join(", ");
713
717
  lines.push(` Tabs = {${tabValues}}`);
714
718
  } else if (hasProjectConstant) {
@@ -804,7 +808,7 @@ var init_tla = __esm(() => {
804
808
  if (hasStateConstants) {
805
809
  this.generateConstantDeclarations(config.state, false);
806
810
  }
807
- if (hasPerMessageBounds) {
811
+ if (hasPerMessageBounds && config.messages.perMessageBounds) {
808
812
  for (const [msgType, _bound] of Object.entries(config.messages.perMessageBounds)) {
809
813
  const constName = `MaxMessages_${msgType}`;
810
814
  this.line(`,${constName}`);
@@ -831,15 +835,15 @@ var init_tla = __esm(() => {
831
835
  }
832
836
  addFieldConstants(field, fieldConfig, constName, first) {
833
837
  let isFirst = first;
834
- if ("maxLength" in fieldConfig && fieldConfig.maxLength !== null) {
838
+ if ("maxLength" in fieldConfig && fieldConfig["maxLength"] !== null) {
835
839
  this.line(`${isFirst ? "" : ","}${constName}_MaxLength \\* Max length for ${field}`);
836
840
  isFirst = false;
837
841
  }
838
- if ("max" in fieldConfig && fieldConfig.max !== null) {
842
+ if ("max" in fieldConfig && fieldConfig["max"] !== null) {
839
843
  this.line(`${isFirst ? "" : ","}${constName}_Max \\* Max value for ${field}`);
840
844
  isFirst = false;
841
845
  }
842
- if ("maxSize" in fieldConfig && fieldConfig.maxSize !== null) {
846
+ if ("maxSize" in fieldConfig && fieldConfig["maxSize"] !== null) {
843
847
  this.line(`${isFirst ? "" : ","}${constName}_MaxSize \\* Max size for ${field}`);
844
848
  isFirst = false;
845
849
  }
@@ -998,7 +1002,6 @@ var init_tla = __esm(() => {
998
1002
  const messageTypeSet = validMessageTypes.map((t) => `"${t}"`).join(", ");
999
1003
  this.line(`UserMessageTypes == {${messageTypeSet}}`);
1000
1004
  this.line("");
1001
- this.filteredMessageTypes = validMessageTypes;
1002
1005
  if (config.messages.symmetry && config.messages.symmetry.length > 0) {
1003
1006
  this.addSymmetrySets(config.messages.symmetry, validMessageTypes);
1004
1007
  }
@@ -1025,6 +1028,8 @@ var init_tla = __esm(() => {
1025
1028
  }
1026
1029
  for (let i = 0;i < validSymmetryGroups.length; i++) {
1027
1030
  const group = validSymmetryGroups[i];
1031
+ if (!group)
1032
+ continue;
1028
1033
  const setName = `SymmetrySet${i + 1}`;
1029
1034
  const setValues = group.map((t) => `"${t}"`).join(", ");
1030
1035
  this.line(`${setName} == {${setValues}}`);
@@ -1038,7 +1043,8 @@ var init_tla = __esm(() => {
1038
1043
  console.log(`[INFO] [TLAGenerator] Symmetry reduction: ${validSymmetryGroups.length} independent symmetry groups ` + `(${validSymmetryGroups.map((g) => g.length).join(", ")} message types)`);
1039
1044
  } else {
1040
1045
  this.line(`Symmetry == Permutations(SymmetrySet1)`);
1041
- console.log(`[INFO] [TLAGenerator] Symmetry reduction: 1 symmetry group with ${validSymmetryGroups[0].length} message types`);
1046
+ const onlyGroup = validSymmetryGroups[0];
1047
+ console.log(`[INFO] [TLAGenerator] Symmetry reduction: 1 symmetry group with ${onlyGroup?.length ?? 0} message types`);
1042
1048
  }
1043
1049
  this.symmetrySets = ["Symmetry"];
1044
1050
  this.line("");
@@ -1221,11 +1227,12 @@ var init_tla = __esm(() => {
1221
1227
  addPayloadRefsFromHandler(handler, fields) {
1222
1228
  for (const text of this.collectHandlerTexts(handler)) {
1223
1229
  const numMatch = TLAGenerator.NUMERIC_PAYLOAD_PATTERN.exec(text);
1224
- if (numMatch)
1230
+ if (numMatch?.[1])
1225
1231
  fields.set(numMatch[1], "0..2");
1226
1232
  for (const m of text.matchAll(TLAGenerator.PAYLOAD_REF_PATTERN)) {
1227
- if (!fields.has(m[1]))
1228
- fields.set(m[1], TLAGenerator.inferFieldType(m[1]));
1233
+ const name = m[1];
1234
+ if (name && !fields.has(name))
1235
+ fields.set(name, TLAGenerator.inferFieldType(name));
1229
1236
  }
1230
1237
  }
1231
1238
  }
@@ -1404,12 +1411,36 @@ var init_tla = __esm(() => {
1404
1411
  }
1405
1412
  this.emitPreconditions(allPreconditions);
1406
1413
  const validAssignments = this.processAssignments(allAssignments, config.state);
1407
- const usedUnchanged = this.emitStateUpdates(validAssignments, allPreconditions);
1408
- if (!usedUnchanged) {
1409
- this.emitPostconditions(allPostconditions);
1410
- }
1414
+ this.emitStateUpdates(validAssignments, allPreconditions);
1411
1415
  this.indent--;
1412
1416
  this.line("");
1417
+ this.recordPostconditionProperty(messageType, actionName, allPostconditions);
1418
+ }
1419
+ recordPostconditionProperty(messageType, actionName, postconditions) {
1420
+ if (postconditions.length === 0)
1421
+ return;
1422
+ const predicateClauses = postconditions.map((pc) => this.tsExpressionToTLA(pc.expression, true)).filter((p) => p && p.length > 0).map((p) => p.replace(/\[ctx\]/g, "[target]"));
1423
+ if (predicateClauses.length === 0)
1424
+ return;
1425
+ const conjunction = predicateClauses.length === 1 ? predicateClauses[0] : predicateClauses.map((c) => ` /\\ ${c}`).join(`
1426
+ `);
1427
+ const propertyName = `EnsuresAfter_${actionName}`;
1428
+ const messages = postconditions.map((pc) => pc.message).filter((m) => Boolean(m)).join("; ");
1429
+ const target = `
1430
+ \\A m \\in 1..Len(messages) :
1431
+ ` + ` (messages[m].status = "pending"
1432
+ ` + ` /\\ messages'[m].status = "delivered"
1433
+ ` + ` /\\ messages[m].msgType = "${messageType}")
1434
+ ` + ` => \\A target \\in messages[m].targets :
1435
+ ` + ` (target \\in Contexts /\\ ports[target] = "connected")
1436
+ ` + ` =>
1437
+ ` + (predicateClauses.length === 1 ? ` ${predicateClauses[0]}` : conjunction);
1438
+ this.temporalProperties.push({
1439
+ name: propertyName,
1440
+ description: messages.length > 0 ? `ensures(...) for ${messageType}: ${messages}` : `ensures(...) for ${messageType}`,
1441
+ type: "step-always",
1442
+ target
1443
+ });
1413
1444
  }
1414
1445
  emitPreconditions(preconditions) {
1415
1446
  for (const precondition of preconditions) {
@@ -1418,14 +1449,6 @@ var init_tla = __esm(() => {
1418
1449
  this.line(`/\\ ${tlaExpr}${comment}`);
1419
1450
  }
1420
1451
  }
1421
- emitPostconditions(postconditions) {
1422
- for (const postcondition of postconditions) {
1423
- const tlaExpr = this.tsExpressionToTLA(postcondition.expression, true);
1424
- const message = postcondition.message ?? "ensures failed";
1425
- const escapedMessage = message.replace(/"/g, "\\\"");
1426
- this.line(`/\\ Assert(${tlaExpr}, "${escapedMessage}")`);
1427
- }
1428
- }
1429
1452
  processAssignments(assignments, state) {
1430
1453
  return assignments.filter((a) => this.isFieldModeled(a.field, state)).filter((a) => this.shouldIncludeAssignment(a, state)).map((a) => this.mapNullAssignment(a, state));
1431
1454
  }
@@ -1462,7 +1485,7 @@ var init_tla = __esm(() => {
1462
1485
  if ("nullable" in fieldConfig && fieldConfig.nullable)
1463
1486
  return assignment;
1464
1487
  if ("values" in fieldConfig && fieldConfig.values) {
1465
- const nullValue = fieldConfig.values[fieldConfig.values.length - 1];
1488
+ const nullValue = fieldConfig.values[fieldConfig.values.length - 1] ?? null;
1466
1489
  return { ...assignment, value: nullValue };
1467
1490
  }
1468
1491
  return assignment;
@@ -1673,7 +1696,6 @@ var init_tla = __esm(() => {
1673
1696
  result = result.replace(/(\w+(?:\.\w+)*)\.includes\(([^)]+)\)/g, (_match, arrayRef, item) => {
1674
1697
  return `${item.trim()} \\in ${arrayRef}`;
1675
1698
  });
1676
- const _indexMap = new Map;
1677
1699
  result = result.replace(/(\w+(?:\.\w+)*)\[(\d+)\]|\]\[(\d+)\]/g, (_match, identPart, index1, index2) => {
1678
1700
  if (identPart) {
1679
1701
  const newIndex2 = Number.parseInt(index1, 10) + 1;
@@ -2070,7 +2092,6 @@ var init_tla = __esm(() => {
2070
2092
  }
2071
2093
  this.line("\\* State constraint to bound state space");
2072
2094
  this.addStateConstraint(config, _analysis);
2073
- this.line("=============================================================================");
2074
2095
  }
2075
2096
  addTemporalConstraints(constraints) {
2076
2097
  this.line("\\* Tier 2: Temporal constraint invariants");
@@ -2078,6 +2099,8 @@ var init_tla = __esm(() => {
2078
2099
  this.line("");
2079
2100
  for (let i = 0;i < constraints.length; i++) {
2080
2101
  const constraint = constraints[i];
2102
+ if (!constraint)
2103
+ continue;
2081
2104
  const invName = `TemporalConstraint${i + 1}`;
2082
2105
  if (constraint.description) {
2083
2106
  this.line(`\\* ${constraint.description}`);
@@ -2093,9 +2116,8 @@ var init_tla = __esm(() => {
2093
2116
  this.extractedInvariants.push({
2094
2117
  name: invName,
2095
2118
  description: constraint.description || `${constraint.before} must happen before ${constraint.after}`,
2096
- condition: "",
2097
- confidence: "high",
2098
- source: { file: "", line: 0, column: 0 }
2119
+ expression: `${constraint.before} happens-before ${constraint.after}`,
2120
+ location: { file: "", line: 0 }
2099
2121
  });
2100
2122
  }
2101
2123
  }
@@ -2108,7 +2130,7 @@ var init_tla = __esm(() => {
2108
2130
  this.indent++;
2109
2131
  if (needsConjunction) {
2110
2132
  this.line("/\\ Len(messages) <= MaxMessages");
2111
- if (hasPerMessageBounds) {
2133
+ if (hasPerMessageBounds && config.messages.perMessageBounds) {
2112
2134
  for (const [msgType, _bound] of Object.entries(config.messages.perMessageBounds)) {
2113
2135
  const constName = `MaxMessages_${msgType}`;
2114
2136
  this.line(`/\\ Cardinality({m \\in DOMAIN messages : messages[m].msgType = "${msgType}"}) <= ${constName}`);
@@ -2154,7 +2176,6 @@ var init_tla = __esm(() => {
2154
2176
  this.line(propDef);
2155
2177
  this.line("");
2156
2178
  }
2157
- this.line("=============================================================================");
2158
2179
  }
2159
2180
  fieldConfigToTLAType(_fieldPath, fieldConfig, _config) {
2160
2181
  const typeResult = this.tryAbstractType(fieldConfig) || this.tryBooleanType(fieldConfig) || this.tryEnumType(fieldConfig) || this.tryArrayType(fieldConfig) || this.tryExplicitNumberType(fieldConfig) || this.tryNumberType(fieldConfig) || this.tryStringType(fieldConfig) || this.tryMapType(fieldConfig);
@@ -6501,6 +6522,8 @@ class HandlerExtractor {
6501
6522
  if (match) {
6502
6523
  const signalName = match[1];
6503
6524
  const fieldName = match[2];
6525
+ if (!signalName)
6526
+ return;
6504
6527
  if (fieldName) {
6505
6528
  signals.push(`${signalName}_${fieldName}`);
6506
6529
  } else {
@@ -7693,4 +7716,4 @@ main().catch((error) => {
7693
7716
  process.exit(1);
7694
7717
  });
7695
7718
 
7696
- //# debugId=BB9760A4D35CDBCE64756E2164756E21
7719
+ //# debugId=616D5E99FD251E9364756E2164756E21