tla-ts 0.0.1 → 0.0.3-dev.a50fc89

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.
Files changed (71) hide show
  1. package/README.md +81 -42
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.d.cts +215 -30
  4. package/dist/index.d.ts +215 -30
  5. package/dist/index.js +1 -1
  6. package/dist/parallel-worker.cjs +2 -2
  7. package/dist/parallel-worker.js +2 -2
  8. package/dist/parallel.cjs +1 -1
  9. package/dist/parallel.js +2 -2
  10. package/dist/run-cli.cjs +20 -1
  11. package/dist/run-cli.js +20 -1
  12. package/dist/transfer.cjs +388 -39
  13. package/dist/transfer.js +388 -39
  14. package/package.json +6 -2
  15. package/src/ast.ts +122 -5
  16. package/src/bags.ts +161 -71
  17. package/src/builtins.ts +203 -23
  18. package/src/bundled-modules.ts +63 -32
  19. package/src/check.ts +945 -238
  20. package/src/cli-options.ts +58 -0
  21. package/src/codegen.ts +52 -18
  22. package/src/config.ts +39 -11
  23. package/src/environment.ts +485 -140
  24. package/src/errors.ts +59 -1
  25. package/src/evaluate.ts +489 -137
  26. package/src/exit-codes.ts +75 -0
  27. package/src/fingerprints.ts +2 -2
  28. package/src/index.ts +9 -4
  29. package/src/instances.ts +221 -66
  30. package/src/java-overrides.ts +241 -0
  31. package/src/json.ts +153 -72
  32. package/src/levels.ts +850 -0
  33. package/src/lexer.ts +103 -28
  34. package/src/liveness.ts +47 -91
  35. package/src/obligation-action.ts +384 -0
  36. package/src/obligation-anon.ts +575 -0
  37. package/src/obligation-deref.ts +637 -0
  38. package/src/obligation-expression.ts +1060 -0
  39. package/src/obligation-format.ts +406 -0
  40. package/src/obligation-generate.ts +1074 -0
  41. package/src/obligation-levels.ts +329 -0
  42. package/src/obligation-module.ts +1042 -0
  43. package/src/obligation-printer.ts +889 -0
  44. package/src/obligation-proof.ts +76 -0
  45. package/src/obligation-source.ts +1084 -0
  46. package/src/obligation-tuples.ts +184 -0
  47. package/src/obligations.ts +316 -0
  48. package/src/parallel-worker.ts +57 -28
  49. package/src/parallel.ts +116 -62
  50. package/src/parser.ts +958 -205
  51. package/src/pretty-print.ts +259 -0
  52. package/src/randomization.ts +24 -113
  53. package/src/resolve.ts +472 -41
  54. package/src/run-cli.ts +427 -61
  55. package/src/runtime.ts +63 -28
  56. package/src/spec-description.ts +509 -0
  57. package/src/standard-levels.ts +105 -0
  58. package/src/standard-modules.ts +223 -92
  59. package/src/subexpressions.ts +21 -35
  60. package/src/substitution-levels.ts +184 -0
  61. package/src/successors.ts +261 -46
  62. package/src/symmetry.ts +65 -21
  63. package/src/tableau.ts +43 -37
  64. package/src/tlc-ext.ts +120 -33
  65. package/src/tlc-module.ts +71 -47
  66. package/src/tlc-modules.ts +1022 -0
  67. package/src/tlc-order.ts +497 -0
  68. package/src/tlc-random.ts +411 -0
  69. package/src/tlc-summary.ts +109 -0
  70. package/src/transfer.ts +26 -5
  71. package/src/values.ts +1231 -176
package/src/tlc-module.ts CHANGED
@@ -1,34 +1,40 @@
1
- import { TlaEvaluationError } from "./errors";
1
+ import { TlaModuleError } from "./errors";
2
+ import { EXIT_STATUS } from "./exit-codes";
2
3
  import type { Builtin } from "./evaluate";
4
+ import { prettyPrint } from "./pretty-print";
3
5
  import {
4
6
  defineConstant,
5
7
  defineHigherOrderOperator,
6
8
  defineOperator,
7
9
  defineStateOperator,
8
10
  getElements,
11
+ getEnumerableSet,
12
+ getFunction,
9
13
  getOperator,
10
14
  getSequence,
11
15
  getValue,
12
16
  } from "./builtins";
13
17
  import { getNamedRegisters, NAMED_REGISTER_PREFIX, type CheckerRuntime } from "./runtime";
18
+ import { createActionRecord } from "./tlc-ext";
19
+ import { getRandomElement } from "./tlc-random";
14
20
  import {
21
+ ANY_SET,
15
22
  createFunction,
16
23
  createRecord,
17
24
  createSet,
18
25
  createTuple,
26
+ createWrittenFunction,
19
27
  formatValue,
20
- toFiniteFunction,
28
+ getWrittenPairs,
29
+ toFiniteSet,
21
30
  type Value,
31
+ rankString,
22
32
  } from "./values";
23
33
 
24
- const createLocationRecord = () =>
25
- createRecord([
26
- ["beginLine", 0],
27
- ["beginColumn", 0],
28
- ["endLine", 0],
29
- ["endColumn", 0],
30
- ["module", "--unknown--"],
31
- ]);
34
+ const padTime = (value: number) => String(value).padStart(2, "0");
35
+
36
+ const formatCalendarVersion = (date: Date) =>
37
+ `${date.getUTCFullYear()}.${padTime(date.getUTCMonth() + 1)}.${padTime(date.getUTCDate())}.${padTime(date.getUTCHours())}${padTime(date.getUTCMinutes())}${padTime(date.getUTCSeconds())}`;
32
38
 
33
39
  const getRegisterFunction = <Key extends Value>(registers: Map<Key, Value>) =>
34
40
  createFunction([...registers].map(([key, value]): [Value, Value] => [key, createTuple([value])]));
@@ -37,7 +43,7 @@ const getRuntimeValue = (
37
43
  runtime: CheckerRuntime,
38
44
  key: string,
39
45
  state: (Value | undefined)[] | undefined,
40
- ): Value => {
46
+ ) => {
41
47
  const duration = Math.floor((Date.now() - runtime.startedAt) / 1000);
42
48
  switch (key) {
43
49
  case "level":
@@ -67,23 +73,24 @@ const getRuntimeValue = (
67
73
  ["mode", "bfs"],
68
74
  ["deadlock", runtime.checkDeadlock],
69
75
  ["worker", 1],
70
- ["seed", "0"],
76
+ ["seed", String(runtime.seed)],
71
77
  ["fingerprint", "0"],
72
- ["install", ""],
78
+ ["install", "unknown"],
73
79
  ]);
74
- case "revision":
80
+ case "revision": {
81
+ const now = new Date();
75
82
  return createRecord([
76
83
  ["count", 0],
77
- ["timestamp", 0],
78
- ["date", "1970-01-01T00:00:00.0Z"],
79
- ["tag", "tla-ts"],
80
- ["calver", "0"],
84
+ ["timestamp", Math.floor(now.getTime() / 1000)],
85
+ ["date", rankString(`${now.toISOString().slice(0, 19)}.${now.getUTCMilliseconds()}Z`)],
86
+ ["tag", "development"],
87
+ ["calver", rankString(formatCalendarVersion(new Date(runtime.startedAt)))],
81
88
  ]);
89
+ }
90
+ case "spec":
91
+ return runtime.getSpecification();
82
92
  case "action":
83
- return createRecord([
84
- ["name", "UnnamedAction"],
85
- ["location", createLocationRecord()],
86
- ]);
93
+ return createActionRecord(undefined);
87
94
  case "all":
88
95
  return getRegisterFunction(runtime.registers);
89
96
  case "all:named":
@@ -91,11 +98,11 @@ const getRuntimeValue = (
91
98
  }
92
99
  if (key.startsWith(NAMED_REGISTER_PREFIX)) {
93
100
  const value = getNamedRegisters(runtime).get(key);
94
- if (value === undefined) throw new TlaEvaluationError(`TLCGet(${key}) was undefined.`);
101
+ if (value === undefined) throw new TlaModuleError(`TLCGet(${key}) was undefined.`);
95
102
  return value;
96
103
  }
97
- if (key.startsWith("-D")) return runtime.properties.get(key.slice(2)) ?? key;
98
- throw new TlaEvaluationError(`TLCGet(${key}) was undefined.`);
104
+ if (key.startsWith("-D")) return rankString(runtime.properties.get(key.slice(2)) ?? key);
105
+ throw new TlaModuleError(`TLCGet(${key}) was undefined.`);
99
106
  };
100
107
 
101
108
  const getPermutations = (elements: Value[]): Value[][] =>
@@ -108,24 +115,34 @@ const getPermutations = (elements: Value[]): Value[][] =>
108
115
  ]),
109
116
  );
110
117
 
118
+ // TLC sorts the value of a TLCEval argument that it caches, with every value inside it.
119
+ const normalizeDeeply = (value: Value): void => {
120
+ if (typeof value !== "object") return;
121
+ if (value.kind === "Set" || value.kind === "MixedSet") {
122
+ toFiniteSet(value).elements.forEach(normalizeDeeply);
123
+ }
124
+ if (value.kind === "Function") value.range.forEach(normalizeDeeply);
125
+ };
126
+
111
127
  export const createTlcOperators = (
112
128
  print: (text: string) => void,
113
129
  runtime: CheckerRuntime,
114
130
  ): Builtin[] => [
115
131
  defineOperator("Print", 2, (args) => {
116
132
  print(
117
- `${formatValue(getValue(args, 0, "Print"), true)} ${formatValue(getValue(args, 1, "Print"), true)}`,
133
+ `${prettyPrint(formatValue(getValue(args, 0, "Print"), true, true))} ${prettyPrint(formatValue(getValue(args, 1, "Print"), true, true))}`,
118
134
  );
119
135
  return getValue(args, 1, "Print");
120
136
  }),
121
137
  defineOperator("PrintT", 1, (args) => {
122
- print(formatValue(getValue(args, 0, "PrintT"), true));
138
+ print(prettyPrint(formatValue(getValue(args, 0, "PrintT"), true, true)));
123
139
  return true;
124
140
  }),
125
141
  defineOperator("Assert", 2, (args) => {
126
142
  if (getValue(args, 0, "Assert") !== true) {
127
- throw new TlaEvaluationError(
128
- `The first argument of Assert evaluated to FALSE; the second argument was:\n${formatValue(getValue(args, 1, "Assert"))}`,
143
+ throw new TlaModuleError(
144
+ `The first argument of Assert evaluated to FALSE; the second argument was:\n${prettyPrint(formatValue(getValue(args, 1, "Assert")))}`,
145
+ EXIT_STATUS.assertViolation,
129
146
  );
130
147
  }
131
148
  return true;
@@ -135,15 +152,18 @@ export const createTlcOperators = (
135
152
  createFunction([[getValue(args, 0, ":>"), getValue(args, 1, ":>")]]),
136
153
  ),
137
154
  defineOperator("@@", 2, (args) => {
138
- const left = toFiniteFunction(getValue(args, 0, "@@"));
139
- const right = toFiniteFunction(getValue(args, 1, "@@"));
140
- return createFunction([
141
- ...left.domain.map((key, index): [Value, Value] => [key, left.range[index]]),
142
- ...right.domain.map((key, index): [Value, Value] => [key, right.range[index]]),
143
- ]);
155
+ const left = getFunction(args, 0, "@@");
156
+ const right = getFunction(args, 1, "@@");
157
+ return createWrittenFunction([...getWrittenPairs(left), ...getWrittenPairs(right)]);
158
+ }),
159
+ defineOperator("ToString", 1, (args) =>
160
+ rankString(formatValue(getValue(args, 0, "ToString"), true)),
161
+ ),
162
+ defineOperator("TLCEval", 1, (args) => {
163
+ const value = getValue(args, 0, "TLCEval");
164
+ normalizeDeeply(value);
165
+ return value;
144
166
  }),
145
- defineOperator("ToString", 1, (args) => formatValue(getValue(args, 0, "ToString"))),
146
- defineOperator("TLCEval", 1, (args) => getValue(args, 0, "TLCEval")),
147
167
  defineOperator("Permutations", 1, (args) => {
148
168
  const elements = getElements(args, 0, "Permutations");
149
169
  return createSet(
@@ -171,11 +191,11 @@ export const createTlcOperators = (
171
191
  const key = getValue(args, 0, "TLCGet");
172
192
  if (typeof key === "number" && key >= 0) {
173
193
  const value = runtime.registers.get(key);
174
- if (value === undefined) throw new TlaEvaluationError(`TLCGet(${key}) was undefined.`);
194
+ if (value === undefined) throw new TlaModuleError(`TLCGet(${key}) was undefined.`);
175
195
  return value;
176
196
  }
177
197
  if (typeof key !== "string") {
178
- throw new TlaEvaluationError(
198
+ throw new TlaModuleError(
179
199
  `The argument of TLCGet should be a nonnegative integer, but instead it is:\n${formatValue(key)}`,
180
200
  );
181
201
  }
@@ -192,7 +212,13 @@ export const createTlcOperators = (
192
212
  if (value === true) runtime.isStopped = true;
193
213
  return true;
194
214
  }
195
- if (key === "pause") return true;
215
+ if (key === "pause") {
216
+ if (value === true) {
217
+ print("Press enter to resume model checking.");
218
+ runtime.pause();
219
+ }
220
+ return true;
221
+ }
196
222
  if (typeof key === "string" && key.startsWith(NAMED_REGISTER_PREFIX)) {
197
223
  runtime.namedRegisters.set(key, value);
198
224
  return true;
@@ -201,14 +227,12 @@ export const createTlcOperators = (
201
227
  runtime.properties.set(key.slice(2), formatValue(value));
202
228
  return true;
203
229
  }
204
- throw new TlaEvaluationError(
230
+ throw new TlaModuleError(
205
231
  `The first argument of TLCSet should be a nonnegative integer, but instead it is:\n${formatValue(key)}`,
206
232
  );
207
233
  }),
208
- defineConstant("Any", { kind: "InfiniteSet", name: "Any" }),
209
- defineOperator("RandomElement", 1, (args) => {
210
- const elements = getElements(args, 0, "RandomElement");
211
- if (elements.length === 0) throw new TlaEvaluationError("RandomElement of the empty set");
212
- return elements[Math.floor(runtime.random() * elements.length)];
213
- }),
234
+ defineConstant("Any", ANY_SET),
235
+ defineOperator("RandomElement", 1, (args) =>
236
+ getRandomElement(getEnumerableSet(args, 0, "RandomElement"), runtime.getRandom()),
237
+ ),
214
238
  ];