tla-ts 0.0.1 → 0.0.2
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/README.md +34 -41
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +166 -30
- package/dist/index.d.ts +166 -30
- package/dist/index.js +1 -1
- package/dist/parallel-worker.cjs +2 -2
- package/dist/parallel-worker.js +2 -2
- package/dist/parallel.cjs +1 -1
- package/dist/parallel.js +2 -2
- package/dist/run-cli.cjs +2 -1
- package/dist/run-cli.js +2 -1
- package/dist/transfer.cjs +388 -39
- package/dist/transfer.js +388 -39
- package/package.json +4 -2
- package/src/ast.ts +82 -5
- package/src/bags.ts +161 -71
- package/src/builtins.ts +203 -23
- package/src/bundled-modules.ts +63 -32
- package/src/check.ts +904 -230
- package/src/codegen.ts +52 -18
- package/src/config.ts +39 -11
- package/src/environment.ts +485 -140
- package/src/errors.ts +22 -0
- package/src/evaluate.ts +486 -136
- package/src/exit-codes.ts +75 -0
- package/src/fingerprints.ts +2 -2
- package/src/index.ts +9 -4
- package/src/instances.ts +221 -66
- package/src/java-overrides.ts +241 -0
- package/src/json.ts +153 -72
- package/src/levels.ts +850 -0
- package/src/lexer.ts +97 -27
- package/src/liveness.ts +47 -91
- package/src/parallel-worker.ts +57 -28
- package/src/parallel.ts +116 -62
- package/src/parser.ts +703 -183
- package/src/pretty-print.ts +259 -0
- package/src/randomization.ts +24 -113
- package/src/resolve.ts +472 -41
- package/src/run-cli.ts +142 -44
- package/src/runtime.ts +63 -28
- package/src/spec-description.ts +509 -0
- package/src/standard-levels.ts +105 -0
- package/src/standard-modules.ts +223 -92
- package/src/subexpressions.ts +21 -35
- package/src/substitution-levels.ts +184 -0
- package/src/successors.ts +261 -46
- package/src/symmetry.ts +65 -21
- package/src/tableau.ts +43 -37
- package/src/tlc-ext.ts +120 -33
- package/src/tlc-module.ts +71 -47
- package/src/tlc-modules.ts +1022 -0
- package/src/tlc-order.ts +497 -0
- package/src/tlc-random.ts +411 -0
- package/src/tlc-summary.ts +109 -0
- package/src/transfer.ts +4 -4
- package/src/values.ts +1186 -164
package/src/environment.ts
CHANGED
|
@@ -12,18 +12,40 @@ import { BUNDLED_MODULES } from "./bundled-modules";
|
|
|
12
12
|
import type { ConfigValue, ModelConfig } from "./config";
|
|
13
13
|
import type { FileSystem } from "./json";
|
|
14
14
|
import { TlaConfigError, TlaEvaluationError, TlaSyntaxError } from "./errors";
|
|
15
|
-
import {
|
|
15
|
+
import { EXIT_STATUS, setExitCode } from "./exit-codes";
|
|
16
|
+
import {
|
|
17
|
+
createBigNumberError,
|
|
18
|
+
createRealNumberError,
|
|
19
|
+
getChildren,
|
|
20
|
+
isConstantLevel,
|
|
21
|
+
isTlcInteger,
|
|
22
|
+
type Builtin,
|
|
23
|
+
type Environment,
|
|
24
|
+
} from "./evaluate";
|
|
16
25
|
import {
|
|
17
26
|
createInstantiation,
|
|
18
27
|
getEnabledVariableName,
|
|
19
28
|
renameLocals,
|
|
20
29
|
withLetInstances,
|
|
21
30
|
} from "./instances";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
31
|
+
import { overrideDefinitions } from "./java-overrides";
|
|
32
|
+
import { extractModule, parseModule } from "./parser";
|
|
33
|
+
import {
|
|
34
|
+
checkRedefinitions,
|
|
35
|
+
getArity,
|
|
36
|
+
isBefore,
|
|
37
|
+
KEY_SEPARATOR,
|
|
38
|
+
LOCAL_RESOLUTION,
|
|
39
|
+
resolveModule,
|
|
40
|
+
resolveSubstitutions,
|
|
41
|
+
type ModuleSymbol,
|
|
42
|
+
type Symbols,
|
|
43
|
+
} from "./resolve";
|
|
24
44
|
import { createRuntime } from "./runtime";
|
|
25
|
-
import { CORE_OPERATORS, getStandardModule } from "./standard-modules";
|
|
45
|
+
import { CORE_OPERATORS, getStandardModule, STANDARD_DEPENDENCIES } from "./standard-modules";
|
|
26
46
|
import { resolveInstanceSubexpressions, resolveModuleSubexpressions } from "./subexpressions";
|
|
47
|
+
import { checkModuleLevels } from "./levels";
|
|
48
|
+
import { checkInstances, type InstanceCheck } from "./substitution-levels";
|
|
27
49
|
import {
|
|
28
50
|
checkInteger,
|
|
29
51
|
createModelValue,
|
|
@@ -33,21 +55,36 @@ import {
|
|
|
33
55
|
type Value,
|
|
34
56
|
} from "./values";
|
|
35
57
|
|
|
36
|
-
|
|
58
|
+
interface EnvironmentOptions {
|
|
59
|
+
source: string;
|
|
37
60
|
loadModule: ((name: string) => string | undefined) | undefined;
|
|
61
|
+
loadClass?: (name: string) => Uint8Array | undefined;
|
|
38
62
|
print: (text: string) => void;
|
|
39
63
|
files: FileSystem;
|
|
64
|
+
seed?: bigint;
|
|
40
65
|
}
|
|
41
66
|
|
|
42
|
-
|
|
67
|
+
interface Specification {
|
|
43
68
|
environment: Environment;
|
|
44
69
|
assumptions: Assumption[];
|
|
70
|
+
variableLocations: SourceLocation[];
|
|
71
|
+
instanceActions: Map<string, InstanceAction>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface InstanceAction {
|
|
75
|
+
name: string;
|
|
76
|
+
location: SourceLocation;
|
|
45
77
|
}
|
|
46
78
|
|
|
47
79
|
const toValue = (value: ConfigValue): Value => {
|
|
48
80
|
switch (value.kind) {
|
|
49
81
|
case "Number":
|
|
50
|
-
|
|
82
|
+
try {
|
|
83
|
+
return checkInteger(value.value);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
// TLC fails with an unexpected exception on a configuration number too big for it.
|
|
86
|
+
throw setExitCode(error, EXIT_STATUS.error);
|
|
87
|
+
}
|
|
51
88
|
case "String":
|
|
52
89
|
case "Boolean":
|
|
53
90
|
return value.value;
|
|
@@ -62,11 +99,29 @@ interface LinkedModule {
|
|
|
62
99
|
module: Module;
|
|
63
100
|
constants: Declaration[];
|
|
64
101
|
variables: string[];
|
|
102
|
+
variableLocations: SourceLocation[];
|
|
65
103
|
visible: Symbols;
|
|
66
104
|
exported: Symbols;
|
|
105
|
+
modules: Map<string, LinkedModule>;
|
|
106
|
+
extended: LinkedModule[];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
interface ModuleScope {
|
|
110
|
+
id: string;
|
|
111
|
+
symbols: Symbols;
|
|
112
|
+
modules: Map<string, LinkedModule>;
|
|
113
|
+
nested: Module[];
|
|
67
114
|
}
|
|
68
115
|
|
|
69
|
-
const
|
|
116
|
+
const getDeclarations = (linked: LinkedModule) => [
|
|
117
|
+
...linked.constants,
|
|
118
|
+
...linked.variables.map((variable) => ({ name: variable, arity: 0 })),
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
const createModuleRedefinedError = (module: Module) =>
|
|
122
|
+
new TlaSyntaxError(
|
|
123
|
+
`Multiply-defined module '${module.name}' at line ${module.location.line}, column ${module.location.column}`,
|
|
124
|
+
);
|
|
70
125
|
|
|
71
126
|
const createLocalFunction = (definition: Definition, key: string): Definition => ({
|
|
72
127
|
kind: "Operator",
|
|
@@ -88,37 +143,42 @@ const createLocalFunction = (definition: Definition, key: string): Definition =>
|
|
|
88
143
|
location: definition.location,
|
|
89
144
|
});
|
|
90
145
|
|
|
91
|
-
const createOperatorConstant = (name: string, rows: [Value[], Value][]): Builtin =>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
146
|
+
const createOperatorConstant = (name: string, arity: number, rows: [Value[], Value][]): Builtin => {
|
|
147
|
+
const table = `{ ${rows.map((row) => `<${[...row[0], row[1]].map((value) => formatValue(value)).join(", ")}>`).join(", ")}}`;
|
|
148
|
+
return {
|
|
149
|
+
kind: "Builtin",
|
|
150
|
+
name,
|
|
151
|
+
arity,
|
|
152
|
+
evaluate: (args) => {
|
|
153
|
+
const row = rows.find((candidate) => {
|
|
154
|
+
if (candidate[0].length !== args.length) {
|
|
155
|
+
throw new TlaEvaluationError(
|
|
156
|
+
`Attempted to apply the operator ${table}\nwith wrong number of arguments.`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return candidate[0].every((value, index) => {
|
|
160
|
+
const argument = args[index];
|
|
161
|
+
return (
|
|
162
|
+
!(typeof argument === "object" && argument.kind === "Operator") &&
|
|
163
|
+
valuesEqual(value, argument)
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
if (row) return row[1];
|
|
168
|
+
throw new TlaEvaluationError(
|
|
169
|
+
`Attempted to apply operator:\n${table}\nto arguments (${args.map((argument) => (typeof argument === "object" && argument.kind === "Operator" ? argument.name : formatValue(argument))).join(", ")}), which is undefined.`,
|
|
170
|
+
);
|
|
171
|
+
},
|
|
172
|
+
evaluateUnary: undefined,
|
|
173
|
+
evaluateBinary: undefined,
|
|
174
|
+
};
|
|
175
|
+
};
|
|
113
176
|
|
|
114
177
|
const mentionsName = (expression: Expression, names: Set<string>): boolean =>
|
|
115
178
|
(expression.kind === "Identifier" && names.has(expression.name)) ||
|
|
116
179
|
(expression.kind === "Apply" && names.has(expression.operator)) ||
|
|
117
180
|
getChildren(expression).some((child) => mentionsName(child, names));
|
|
118
181
|
|
|
119
|
-
const getArity = (definition: Definition) =>
|
|
120
|
-
definition.kind === "Operator" ? definition.params.length : 0;
|
|
121
|
-
|
|
122
182
|
const getVariableIndex = (variables: string[], declared: string[]) => {
|
|
123
183
|
const index = new Map(variables.map((name, position) => [name, position]));
|
|
124
184
|
new Set(declared).forEach((name) =>
|
|
@@ -127,20 +187,53 @@ const getVariableIndex = (variables: string[], declared: string[]) => {
|
|
|
127
187
|
return index;
|
|
128
188
|
};
|
|
129
189
|
|
|
190
|
+
const getSubstitutions = (instances: Instance[]) =>
|
|
191
|
+
instances.flatMap((instance) =>
|
|
192
|
+
instance.substitutions.map((substitution) => substitution.expression),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const rejectLiterals = (expressions: Expression[]): void =>
|
|
196
|
+
expressions.forEach((expression) => {
|
|
197
|
+
if (expression.kind === "Decimal") throw createRealNumberError(expression);
|
|
198
|
+
if (expression.kind === "Number" && !isTlcInteger(expression.value)) {
|
|
199
|
+
throw createBigNumberError(expression);
|
|
200
|
+
}
|
|
201
|
+
rejectLiterals(
|
|
202
|
+
expression.kind === "Let"
|
|
203
|
+
? [...getChildren(expression), ...getSubstitutions(expression.instances ?? [])]
|
|
204
|
+
: getChildren(expression),
|
|
205
|
+
);
|
|
206
|
+
});
|
|
207
|
+
|
|
130
208
|
export const createEnvironment = (
|
|
131
|
-
root: Module,
|
|
132
209
|
config: ModelConfig,
|
|
133
210
|
options: EnvironmentOptions,
|
|
134
211
|
): Specification => {
|
|
212
|
+
const root = parseModule(options.source);
|
|
135
213
|
const definitions = new Map<string, Definition>();
|
|
136
214
|
const parameterized = new Map<string, boolean>();
|
|
137
215
|
const builtins = new Map<string, Builtin>(
|
|
138
216
|
CORE_OPERATORS.map((operator) => [operator.name, operator]),
|
|
139
217
|
);
|
|
140
218
|
const standardExports = new Map<string, Symbols>();
|
|
141
|
-
const runtime = createRuntime(config.checkDeadlock);
|
|
219
|
+
const runtime = createRuntime(config.checkDeadlock, options.seed);
|
|
142
220
|
const linkedModules = new Map<string, LinkedModule>();
|
|
221
|
+
const nestedModules = new Map<string, LinkedModule>();
|
|
222
|
+
const linkedList: LinkedModule[] = [];
|
|
223
|
+
const dependencies = new Map<string, Set<string>>();
|
|
224
|
+
const loading: Set<string>[] = [];
|
|
225
|
+
// The top-level modules being linked, to report a cycle of EXTENDS or INSTANCE.
|
|
226
|
+
const linking: string[] = [];
|
|
227
|
+
|
|
228
|
+
const useModule = (name: string, used: Iterable<string>) =>
|
|
229
|
+
loading.forEach((closure) => {
|
|
230
|
+
closure.add(name);
|
|
231
|
+
[...used].forEach((dependency) => closure.add(dependency));
|
|
232
|
+
});
|
|
143
233
|
const copyCount = { value: 0 };
|
|
234
|
+
const createName = (name: string) => `${name}#${copyCount.value++}`;
|
|
235
|
+
const instanceChecks: InstanceCheck[] = [];
|
|
236
|
+
const instanceActions = new Map<string, InstanceAction>();
|
|
144
237
|
|
|
145
238
|
const addStandardModule = (name: string): Symbols | undefined => {
|
|
146
239
|
const cached = standardExports.get(name);
|
|
@@ -161,65 +254,108 @@ export const createEnvironment = (
|
|
|
161
254
|
return exported;
|
|
162
255
|
};
|
|
163
256
|
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
257
|
+
const getStandardSymbols = (name: string) => {
|
|
258
|
+
const symbols = addStandardModule(name);
|
|
259
|
+
if (symbols) useModule(name, STANDARD_DEPENDENCIES.get(name) ?? []);
|
|
260
|
+
return symbols;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// Like TLC, reject a decimal or a big integer anywhere in a module, even where nothing evaluates it.
|
|
264
|
+
const rejectModuleLiterals = (module: Module): Module => {
|
|
265
|
+
rejectLiterals([
|
|
266
|
+
...module.definitions.flatMap((definition) =>
|
|
267
|
+
definition.kind === "Function"
|
|
268
|
+
? [...definition.bounds.map((bound) => bound.set), definition.body]
|
|
269
|
+
: [definition.body],
|
|
270
|
+
),
|
|
271
|
+
...module.assumptions.map((assumption) => assumption.expression),
|
|
272
|
+
...module.theorems.flatMap((theorem) =>
|
|
273
|
+
theorem.statement.kind === "AssumeProve" ? [] : [theorem.statement],
|
|
274
|
+
),
|
|
275
|
+
...getSubstitutions(module.instances),
|
|
276
|
+
]);
|
|
277
|
+
module.modules.forEach(rejectModuleLiterals);
|
|
172
278
|
return module;
|
|
173
279
|
};
|
|
174
|
-
|
|
280
|
+
rejectModuleLiterals(root);
|
|
175
281
|
|
|
176
|
-
const loadModule = (name: string) => {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
282
|
+
const loadModule = (name: string, importer: string) => {
|
|
283
|
+
const source =
|
|
284
|
+
options.loadModule?.(name) ??
|
|
285
|
+
BUNDLED_MODULES.get(name) ??
|
|
286
|
+
extractModule(options.source, name);
|
|
180
287
|
if (source === undefined)
|
|
181
|
-
throw new TlaSyntaxError(
|
|
182
|
-
|
|
288
|
+
throw new TlaSyntaxError(
|
|
289
|
+
`Cannot find source file for module ${name} imported in module ${importer}.`,
|
|
290
|
+
);
|
|
291
|
+
const module = parseModule(source);
|
|
292
|
+
if (module.name !== name) {
|
|
293
|
+
throw new TlaSyntaxError(
|
|
294
|
+
`File name '${name}' does not match the name '${module.name}' of the top level module it contains.`,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
return rejectModuleLiterals(module);
|
|
183
298
|
};
|
|
184
299
|
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return getDefinitionKey(outer, name);
|
|
300
|
+
const linkTopLevel = (parsed: Module) => {
|
|
301
|
+
const cycleStart = linking.indexOf(parsed.name);
|
|
302
|
+
if (cycleStart !== -1) {
|
|
303
|
+
const cycle = [...linking.slice(cycleStart), parsed.name].map((name) => `${name}.tla`);
|
|
304
|
+
throw new TlaSyntaxError(
|
|
305
|
+
`Circular dependency among .tla files; dependency cycle is: ${cycle.join(" --> ")}`,
|
|
306
|
+
);
|
|
193
307
|
}
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
308
|
+
const closure = new Set<string>();
|
|
309
|
+
const nested: Module[] = [];
|
|
310
|
+
linking.push(parsed.name);
|
|
311
|
+
loading.push(closure);
|
|
312
|
+
const linked = linkModule(parsed, {
|
|
313
|
+
id: parsed.name,
|
|
314
|
+
symbols: new Map(),
|
|
315
|
+
modules: new Map(),
|
|
316
|
+
nested,
|
|
317
|
+
});
|
|
318
|
+
loading.pop();
|
|
319
|
+
linking.pop();
|
|
320
|
+
const duplicate = nested.find((module) => closure.has(module.name));
|
|
321
|
+
if (duplicate) throw createModuleRedefinedError(duplicate);
|
|
322
|
+
return { linked, closure };
|
|
197
323
|
};
|
|
198
324
|
|
|
199
|
-
const getLinkedModule = (name: string
|
|
325
|
+
const getLinkedModule = (name: string, importer: string): LinkedModule => {
|
|
326
|
+
const cached = linkedModules.get(name);
|
|
327
|
+
if (cached) {
|
|
328
|
+
useModule(name, dependencies.get(name) ?? []);
|
|
329
|
+
return cached;
|
|
330
|
+
}
|
|
331
|
+
const top = linkTopLevel(loadModule(name, importer));
|
|
332
|
+
linkedModules.set(name, top.linked);
|
|
333
|
+
dependencies.set(name, top.closure);
|
|
334
|
+
useModule(name, top.closure);
|
|
335
|
+
return top.linked;
|
|
336
|
+
};
|
|
200
337
|
|
|
201
338
|
const instantiate = (
|
|
202
339
|
instance: Instance,
|
|
203
340
|
module: Module,
|
|
204
341
|
unit: {
|
|
205
342
|
imported: Symbols;
|
|
343
|
+
importedAt: Map<string, SourceLocation>;
|
|
206
344
|
definitions: Map<string, Definition>;
|
|
207
345
|
getKey: (definition: Definition) => string;
|
|
208
346
|
},
|
|
209
347
|
isParameterFree: boolean,
|
|
348
|
+
nested: LinkedModule | undefined,
|
|
210
349
|
): Symbols => {
|
|
211
|
-
const standardSymbols =
|
|
350
|
+
const standardSymbols = nested ? undefined : getStandardSymbols(instance.module);
|
|
212
351
|
if (standardSymbols) {
|
|
213
352
|
if (instance.name === undefined) return standardSymbols;
|
|
214
353
|
return new Map(
|
|
215
354
|
[...standardSymbols].map(([name, symbol]) => [`${instance.name}!${name}`, symbol]),
|
|
216
355
|
);
|
|
217
356
|
}
|
|
218
|
-
const linked = getLinkedModule(instance.module);
|
|
219
|
-
const declarations =
|
|
220
|
-
...linked.constants,
|
|
221
|
-
...linked.variables.map((variable) => ({ name: variable, arity: 0 })),
|
|
222
|
-
];
|
|
357
|
+
const linked = nested ?? getLinkedModule(instance.module, module.name);
|
|
358
|
+
const declarations = getDeclarations(linked);
|
|
223
359
|
const suffix = `#${copyCount.value++}`;
|
|
224
360
|
const renamed = new Map(instance.params.map((param) => [param.name, `${param.name}${suffix}`]));
|
|
225
361
|
const substitutions = resolveSubstitutions(
|
|
@@ -228,6 +364,13 @@ export const createEnvironment = (
|
|
|
228
364
|
module,
|
|
229
365
|
unit,
|
|
230
366
|
);
|
|
367
|
+
instanceChecks.push({
|
|
368
|
+
module: instance.module,
|
|
369
|
+
instancer: module.name,
|
|
370
|
+
lets: [],
|
|
371
|
+
substitutions,
|
|
372
|
+
location: instance.location,
|
|
373
|
+
});
|
|
231
374
|
const instantiation = createInstantiation({
|
|
232
375
|
params: instance.params.map((param) => ({ ...param, name: `${param.name}${suffix}` })),
|
|
233
376
|
substitutions: new Map(
|
|
@@ -237,22 +380,30 @@ export const createEnvironment = (
|
|
|
237
380
|
getDefinition: (key) => definitions.get(key),
|
|
238
381
|
isParameterized: (key) => parameterized.get(key) === true,
|
|
239
382
|
addDefinition: (name, create) => {
|
|
240
|
-
const key = `${name}@${module.name}
|
|
383
|
+
const key = createName(`${name}@${module.name}`);
|
|
241
384
|
definitions.set(key, create(key));
|
|
242
385
|
parameterized.set(key, !isParameterFree);
|
|
243
386
|
return key;
|
|
244
387
|
},
|
|
388
|
+
createName,
|
|
245
389
|
});
|
|
246
390
|
const declared = new Set(declarations.map((declaration) => declaration.name));
|
|
247
391
|
const symbols: Symbols = new Map();
|
|
248
392
|
linked.exported.forEach((symbol, name) => {
|
|
249
393
|
if (declared.has(name)) return;
|
|
250
394
|
if (instance.name === undefined) {
|
|
251
|
-
|
|
395
|
+
const key = instantiation.getKey(symbol.key);
|
|
396
|
+
if (declarations.length > 0)
|
|
397
|
+
instanceActions.set(key, { name, location: instance.location });
|
|
398
|
+
symbols.set(name, { key, arity: symbol.arity });
|
|
252
399
|
return;
|
|
253
400
|
}
|
|
401
|
+
const key = instantiation.getQualifiedKey(symbol.key);
|
|
402
|
+
if (declarations.length > 0) {
|
|
403
|
+
instanceActions.set(key, { name: `${instance.name}!${name}`, location: instance.location });
|
|
404
|
+
}
|
|
254
405
|
symbols.set(`${instance.name}!${name}`, {
|
|
255
|
-
key
|
|
406
|
+
key,
|
|
256
407
|
arity: symbol.arity + instance.params.length,
|
|
257
408
|
});
|
|
258
409
|
});
|
|
@@ -291,7 +442,7 @@ export const createEnvironment = (
|
|
|
291
442
|
|
|
292
443
|
const getSubstitutionBody = (
|
|
293
444
|
replacement: Expression,
|
|
294
|
-
declaration:
|
|
445
|
+
declaration: OperatorParam,
|
|
295
446
|
location: SourceLocation,
|
|
296
447
|
): { params: OperatorParam[]; body: Expression } => {
|
|
297
448
|
if (declaration.arity === 0) return { params: [], body: replacement };
|
|
@@ -314,10 +465,14 @@ export const createEnvironment = (
|
|
|
314
465
|
};
|
|
315
466
|
};
|
|
316
467
|
|
|
317
|
-
const instantiateLocally = (
|
|
468
|
+
const instantiateLocally = (
|
|
469
|
+
instance: Instance,
|
|
470
|
+
lets: Definition[],
|
|
471
|
+
instancer: string,
|
|
472
|
+
nested: LinkedModule | undefined,
|
|
473
|
+
): Definition[] => {
|
|
318
474
|
const location = instance.location;
|
|
319
|
-
const
|
|
320
|
-
const standardSymbols = addStandardModule(instance.module);
|
|
475
|
+
const standardSymbols = nested ? undefined : getStandardSymbols(instance.module);
|
|
321
476
|
if (standardSymbols) {
|
|
322
477
|
if (instance.name === undefined) return [];
|
|
323
478
|
return [...standardSymbols].map(([name, symbol]) => {
|
|
@@ -325,23 +480,29 @@ export const createEnvironment = (
|
|
|
325
480
|
return createLocalAlias(
|
|
326
481
|
`${instance.name}!${name}`,
|
|
327
482
|
symbol.key,
|
|
328
|
-
[...
|
|
483
|
+
[...instance.params, ...forwarded],
|
|
329
484
|
forwarded,
|
|
330
485
|
location,
|
|
331
486
|
);
|
|
332
487
|
});
|
|
333
488
|
}
|
|
334
|
-
const linked = getLinkedModule(instance.module);
|
|
489
|
+
const linked = nested ?? getLinkedModule(instance.module, instancer);
|
|
335
490
|
const suffix = `#${copyCount.value++}`;
|
|
336
491
|
const explicit = new Map(instance.substitutions.map((item) => [item.name, item.expression]));
|
|
337
|
-
const declarations =
|
|
338
|
-
|
|
339
|
-
...linked.variables.map((variable) => ({ name: variable, arity: 0 })),
|
|
340
|
-
];
|
|
341
|
-
const getReplacement = (declaration: Declaration): Expression =>
|
|
492
|
+
const declarations = getDeclarations(linked);
|
|
493
|
+
const getReplacement = (declaration: OperatorParam): Expression =>
|
|
342
494
|
explicit.get(declaration.name) ?? { kind: "Identifier", name: declaration.name, location };
|
|
343
|
-
|
|
344
|
-
|
|
495
|
+
instanceChecks.push({
|
|
496
|
+
module: instance.module,
|
|
497
|
+
instancer,
|
|
498
|
+
lets,
|
|
499
|
+
substitutions: new Map(
|
|
500
|
+
declarations.map((declaration) => [declaration.name, getReplacement(declaration)]),
|
|
501
|
+
),
|
|
502
|
+
location,
|
|
503
|
+
});
|
|
504
|
+
const instanceNames = new Set(instance.params.map((param) => param.name));
|
|
505
|
+
const isParameterDependent = (declaration: OperatorParam) =>
|
|
345
506
|
mentionsName(getReplacement(declaration), instanceNames);
|
|
346
507
|
const substitutionDefinitions = declarations.map((declaration): Definition => {
|
|
347
508
|
const substitution = getSubstitutionBody(getReplacement(declaration), declaration, location);
|
|
@@ -349,7 +510,7 @@ export const createEnvironment = (
|
|
|
349
510
|
kind: "Operator",
|
|
350
511
|
name: `${declaration.name}${suffix}`,
|
|
351
512
|
params: [
|
|
352
|
-
...(isParameterDependent(declaration) ?
|
|
513
|
+
...(isParameterDependent(declaration) ? instance.params : []),
|
|
353
514
|
...substitution.params,
|
|
354
515
|
],
|
|
355
516
|
body: substitution.body,
|
|
@@ -360,7 +521,7 @@ export const createEnvironment = (
|
|
|
360
521
|
});
|
|
361
522
|
const copies: Definition[] = [];
|
|
362
523
|
const instantiation = createInstantiation({
|
|
363
|
-
params:
|
|
524
|
+
params: instance.params,
|
|
364
525
|
substitutions: new Map(
|
|
365
526
|
declarations.map((declaration): [string, Expression] => [
|
|
366
527
|
declaration.name,
|
|
@@ -374,7 +535,7 @@ export const createEnvironment = (
|
|
|
374
535
|
: {
|
|
375
536
|
kind: "Apply",
|
|
376
537
|
operator: `${declaration.name}${suffix}`,
|
|
377
|
-
args: getLocalArguments(
|
|
538
|
+
args: getLocalArguments(instance.params, location),
|
|
378
539
|
location,
|
|
379
540
|
resolution: LOCAL_RESOLUTION,
|
|
380
541
|
},
|
|
@@ -393,6 +554,7 @@ export const createEnvironment = (
|
|
|
393
554
|
);
|
|
394
555
|
return key;
|
|
395
556
|
},
|
|
557
|
+
createName,
|
|
396
558
|
});
|
|
397
559
|
const declared = new Set(declarations.map((declaration) => declaration.name));
|
|
398
560
|
const aliases = [...linked.exported]
|
|
@@ -400,7 +562,7 @@ export const createEnvironment = (
|
|
|
400
562
|
.map(([name, symbol]) => {
|
|
401
563
|
const key = instantiation.getKey(symbol.key);
|
|
402
564
|
const own = getArguments(symbol.arity);
|
|
403
|
-
const params = [...
|
|
565
|
+
const params = [...instance.params, ...own];
|
|
404
566
|
return createLocalAlias(
|
|
405
567
|
instance.name === undefined ? name : `${instance.name}!${name}`,
|
|
406
568
|
key,
|
|
@@ -418,61 +580,139 @@ export const createEnvironment = (
|
|
|
418
580
|
return definition ? [{ ...definition, name }] : [];
|
|
419
581
|
});
|
|
420
582
|
|
|
421
|
-
const linkModule = (
|
|
422
|
-
const
|
|
423
|
-
|
|
583
|
+
const linkModule = (unlinked: Module, scope: ModuleScope): LinkedModule => {
|
|
584
|
+
const parsed = overrideDefinitions(unlinked, options.loadClass?.(unlinked.name));
|
|
585
|
+
const visible: Symbols = new Map([
|
|
586
|
+
...CORE_OPERATORS.map((operator): [string, ModuleSymbol] => [
|
|
424
587
|
operator.name,
|
|
425
588
|
{ key: operator.name, arity: operator.arity },
|
|
426
589
|
]),
|
|
427
|
-
|
|
590
|
+
...scope.symbols,
|
|
591
|
+
]);
|
|
428
592
|
const exported: Symbols = new Map();
|
|
593
|
+
const modules = new Map<string, LinkedModule>();
|
|
594
|
+
const extended: LinkedModule[] = [];
|
|
429
595
|
const constants = [...parsed.constants];
|
|
430
|
-
const variables =
|
|
596
|
+
const variables = parsed.variables.map((variable) => variable.name);
|
|
597
|
+
const variableLocations = parsed.variables.map((variable) => variable.location);
|
|
431
598
|
const addSymbols = (symbols: Symbols, isExported: boolean) =>
|
|
432
599
|
symbols.forEach((symbol, name) => {
|
|
433
600
|
visible.set(name, symbol);
|
|
434
601
|
if (isExported) exported.set(name, symbol);
|
|
435
602
|
});
|
|
436
|
-
parsed.outer?.extends.forEach((name) =>
|
|
437
|
-
addSymbols(addStandardModule(name) ?? getLinkedModule(name).exported, false),
|
|
438
|
-
);
|
|
439
|
-
parsed.outer?.symbols.forEach((symbol) =>
|
|
440
|
-
visible.set(symbol.name, { key: getOuterKey(parsed, symbol.name), arity: symbol.arity }),
|
|
441
|
-
);
|
|
442
603
|
parsed.extends.forEach((name) => {
|
|
443
|
-
const
|
|
604
|
+
const nested = scope.modules.get(name);
|
|
605
|
+
const standardSymbols = nested ? undefined : getStandardSymbols(name);
|
|
444
606
|
if (standardSymbols) {
|
|
445
607
|
addSymbols(standardSymbols, true);
|
|
446
608
|
return;
|
|
447
609
|
}
|
|
448
|
-
const linked = getLinkedModule(name);
|
|
610
|
+
const linked = nested ?? getLinkedModule(name, parsed.name);
|
|
449
611
|
constants.push(
|
|
450
612
|
...linked.constants.filter((constant) =>
|
|
451
613
|
constants.every((existing) => existing.name !== constant.name),
|
|
452
614
|
),
|
|
453
615
|
);
|
|
454
|
-
|
|
616
|
+
linked.variables.forEach((variable, index) => {
|
|
617
|
+
if (variables.includes(variable)) return;
|
|
618
|
+
variables.push(variable);
|
|
619
|
+
variableLocations.push(linked.variableLocations[index]);
|
|
620
|
+
});
|
|
455
621
|
addSymbols(linked.exported, true);
|
|
622
|
+
linked.modules.forEach((module, moduleName) => modules.set(moduleName, module));
|
|
623
|
+
extended.push(linked);
|
|
456
624
|
});
|
|
457
625
|
parsed.constants.forEach((constant) =>
|
|
458
|
-
exported.set(constant.name, {
|
|
626
|
+
exported.set(constant.name, {
|
|
627
|
+
key: constant.name,
|
|
628
|
+
arity: constant.arity,
|
|
629
|
+
declaration: "Constant",
|
|
630
|
+
}),
|
|
631
|
+
);
|
|
632
|
+
parsed.variables.forEach((variable) =>
|
|
633
|
+
exported.set(variable.name, { key: variable.name, arity: 0, declaration: "Variable" }),
|
|
459
634
|
);
|
|
460
|
-
parsed.variables.forEach((variable) => exported.set(variable, { key: variable, arity: 0 }));
|
|
461
635
|
const isParameterFree = constants.length === 0 && variables.length === 0;
|
|
462
|
-
const getKey = (definition: Definition) =>
|
|
636
|
+
const getKey = (definition: Definition) =>
|
|
637
|
+
parsed === root ? definition.name : `${definition.name}${KEY_SEPARATOR}${scope.id}`;
|
|
638
|
+
const importedAt = new Map<string, SourceLocation>();
|
|
463
639
|
const getUnit = (module: Module) => ({
|
|
464
640
|
imported: visible,
|
|
641
|
+
importedAt,
|
|
465
642
|
definitions: new Map(module.definitions.map((definition) => [definition.name, definition])),
|
|
466
643
|
getKey,
|
|
467
644
|
});
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
645
|
+
const getVisibleModules = () => new Map([...scope.modules, ...modules]);
|
|
646
|
+
const getSymbolsBefore = (location: SourceLocation): Symbols =>
|
|
647
|
+
new Map([
|
|
648
|
+
...visible,
|
|
649
|
+
...[
|
|
650
|
+
...parsed.constants.map((constant) => ({ ...constant, kind: "Constant" as const })),
|
|
651
|
+
...parsed.variables.map((variable) => ({ ...variable, kind: "Variable" as const })),
|
|
652
|
+
]
|
|
653
|
+
.filter((declaration) => isBefore(declaration.location, location))
|
|
654
|
+
.map((declaration): [string, ModuleSymbol] => [
|
|
655
|
+
declaration.name,
|
|
656
|
+
{ key: declaration.name, arity: declaration.arity, declaration: declaration.kind },
|
|
657
|
+
]),
|
|
658
|
+
...parsed.definitions
|
|
659
|
+
.filter((definition) => isBefore(definition.location, location))
|
|
660
|
+
.map((definition): [string, ModuleSymbol] => [
|
|
661
|
+
definition.name,
|
|
662
|
+
{ key: getKey(definition), arity: getArity(definition) },
|
|
663
|
+
]),
|
|
664
|
+
]);
|
|
665
|
+
const linkNested = (nested: Module) => {
|
|
666
|
+
const visibleModules = getVisibleModules();
|
|
667
|
+
if (visibleModules.has(nested.name)) throw createModuleRedefinedError(nested);
|
|
668
|
+
scope.nested.push(nested);
|
|
669
|
+
const linked = linkModule(nested, {
|
|
670
|
+
id: `${scope.id}/${nested.name}`,
|
|
671
|
+
symbols: getSymbolsBefore(nested.location),
|
|
672
|
+
modules: visibleModules,
|
|
673
|
+
nested: scope.nested,
|
|
674
|
+
});
|
|
675
|
+
modules.set(nested.name, linked);
|
|
676
|
+
if (!nestedModules.has(nested.name)) nestedModules.set(nested.name, linked);
|
|
677
|
+
};
|
|
678
|
+
[
|
|
679
|
+
...parsed.instances.map((instance) => ({
|
|
680
|
+
location: instance.location,
|
|
681
|
+
link: () => {
|
|
682
|
+
const symbols = instantiate(
|
|
683
|
+
instance,
|
|
684
|
+
parsed,
|
|
685
|
+
getUnit(parsed),
|
|
686
|
+
isParameterFree,
|
|
687
|
+
getVisibleModules().get(instance.module),
|
|
688
|
+
);
|
|
689
|
+
symbols.forEach((_, name) => {
|
|
690
|
+
if (!visible.has(name)) importedAt.set(name, instance.location);
|
|
691
|
+
});
|
|
692
|
+
addSymbols(symbols, !instance.isLocal);
|
|
693
|
+
},
|
|
694
|
+
})),
|
|
695
|
+
...parsed.modules.map((nested) => ({
|
|
696
|
+
location: nested.location,
|
|
697
|
+
link: () => linkNested(nested),
|
|
698
|
+
})),
|
|
699
|
+
]
|
|
700
|
+
.sort((left, right) => (isBefore(left.location, right.location) ? -1 : 1))
|
|
701
|
+
.forEach((unit) => unit.link());
|
|
702
|
+
checkRedefinitions(parsed, getUnit(parsed));
|
|
703
|
+
const isInstancedAfterDefinition = (nested: Module) => {
|
|
704
|
+
const first = parsed.instances.find((instance) => instance.module === nested.name);
|
|
705
|
+
return first !== undefined && isBefore(nested.location, first.location);
|
|
706
|
+
};
|
|
707
|
+
const getLetModule = (instance: Instance) => {
|
|
708
|
+
const own = parsed.modules.find((nested) => nested.name === instance.module);
|
|
709
|
+
if (!own) return getVisibleModules().get(instance.module);
|
|
710
|
+
return isInstancedAfterDefinition(own) ? modules.get(own.name) : undefined;
|
|
711
|
+
};
|
|
474
712
|
const module = resolveModuleSubexpressions(
|
|
475
|
-
withLetInstances(parsed,
|
|
713
|
+
withLetInstances(parsed, (instance, lets) =>
|
|
714
|
+
instantiateLocally(instance, lets, parsed.name, getLetModule(instance)),
|
|
715
|
+
),
|
|
476
716
|
getAvailableDefinitions(visible),
|
|
477
717
|
);
|
|
478
718
|
resolveModule(module, getUnit(module));
|
|
@@ -484,12 +724,26 @@ export const createEnvironment = (
|
|
|
484
724
|
visible.set(definition.name, symbol);
|
|
485
725
|
if (!definition.isLocal) exported.set(definition.name, symbol);
|
|
486
726
|
});
|
|
487
|
-
|
|
488
|
-
|
|
727
|
+
checkModuleLevels(module, {
|
|
728
|
+
constants: new Set(constants.map((constant) => constant.name)),
|
|
729
|
+
variables: new Set(variables),
|
|
730
|
+
getDefinition: (symbol) => definitions.get(visible.get(symbol)?.key ?? symbol),
|
|
731
|
+
});
|
|
732
|
+
const linked = {
|
|
733
|
+
module,
|
|
734
|
+
constants,
|
|
735
|
+
variables,
|
|
736
|
+
variableLocations,
|
|
737
|
+
visible,
|
|
738
|
+
exported,
|
|
739
|
+
modules,
|
|
740
|
+
extended,
|
|
741
|
+
};
|
|
742
|
+
linkedList.push(linked);
|
|
489
743
|
return linked;
|
|
490
744
|
};
|
|
491
745
|
|
|
492
|
-
const linkedRoot =
|
|
746
|
+
const linkedRoot = linkTopLevel(root).linked;
|
|
493
747
|
const getRootKey = (name: string) => linkedRoot.visible.get(name)?.key ?? name;
|
|
494
748
|
linkedRoot.visible.forEach((symbol, name) => {
|
|
495
749
|
const definition = definitions.get(symbol.key);
|
|
@@ -497,47 +751,80 @@ export const createEnvironment = (
|
|
|
497
751
|
});
|
|
498
752
|
|
|
499
753
|
const assumptions: Assumption[] = [];
|
|
500
|
-
const addAssumptions = (
|
|
501
|
-
if (visited.has(
|
|
502
|
-
visited.add(
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
if (linked) addAssumptions(linked.module, visited);
|
|
506
|
-
});
|
|
507
|
-
assumptions.push(...module.assumptions);
|
|
754
|
+
const addAssumptions = (linked: LinkedModule, visited: Set<LinkedModule>) => {
|
|
755
|
+
if (visited.has(linked)) return;
|
|
756
|
+
visited.add(linked);
|
|
757
|
+
linked.extended.forEach((extended) => addAssumptions(extended, visited));
|
|
758
|
+
assumptions.push(...linked.module.assumptions);
|
|
508
759
|
};
|
|
509
|
-
addAssumptions(linkedRoot
|
|
760
|
+
addAssumptions(linkedRoot, new Set());
|
|
510
761
|
const declaredConstants = linkedRoot.constants.map((constant) => constant.name);
|
|
511
762
|
const variables = linkedRoot.variables;
|
|
512
763
|
|
|
513
|
-
const getScopedKeys = (item: { name: string; module?: string })
|
|
764
|
+
const getScopedKeys = (item: { name: string; module?: string }) => {
|
|
514
765
|
if (item.module === undefined) return [item.name, getRootKey(item.name)];
|
|
515
766
|
if (item.module === root.name || declaredConstants.includes(item.name)) return [];
|
|
516
|
-
|
|
767
|
+
const linked = linkedModules.get(item.module) ?? nestedModules.get(item.module);
|
|
768
|
+
return [linked?.visible.get(item.name)?.key ?? item.name];
|
|
769
|
+
};
|
|
770
|
+
const getKeyArity = (key: string) => {
|
|
771
|
+
const definition = definitions.get(key);
|
|
772
|
+
return definition?.kind === "Operator"
|
|
773
|
+
? definition.params.length
|
|
774
|
+
: (linkedRoot.constants.find((constant) => constant.name === key)?.arity ?? 0);
|
|
517
775
|
};
|
|
518
776
|
const constants = new Map<string, Value>();
|
|
777
|
+
const operatorKeys = new Set<string>();
|
|
778
|
+
const setOperator = (key: string, operator: Builtin) => {
|
|
779
|
+
builtins.set(key, operator);
|
|
780
|
+
definitions.delete(key);
|
|
781
|
+
constants.delete(key);
|
|
782
|
+
operatorKeys.add(key);
|
|
783
|
+
};
|
|
519
784
|
config.constants
|
|
520
785
|
.filter((assignment) => assignment.args === undefined)
|
|
521
786
|
.forEach((assignment) => {
|
|
522
787
|
const value = toValue(assignment.value);
|
|
523
|
-
getScopedKeys(assignment).forEach((key) =>
|
|
788
|
+
getScopedKeys(assignment).forEach((key) => {
|
|
789
|
+
const arity = getKeyArity(key);
|
|
790
|
+
if (arity === 0) constants.set(key, value);
|
|
791
|
+
else
|
|
792
|
+
setOperator(key, {
|
|
793
|
+
kind: "Builtin",
|
|
794
|
+
name: key,
|
|
795
|
+
arity,
|
|
796
|
+
evaluate: () => value,
|
|
797
|
+
evaluateUnary: undefined,
|
|
798
|
+
evaluateBinary: undefined,
|
|
799
|
+
isLazy: true,
|
|
800
|
+
});
|
|
801
|
+
});
|
|
524
802
|
});
|
|
525
|
-
const
|
|
803
|
+
const tables = new Map<string, { name: string; module?: string; rows: [Value[], Value][] }>();
|
|
526
804
|
config.constants.forEach((assignment) => {
|
|
527
805
|
if (assignment.args === undefined) return;
|
|
528
|
-
const
|
|
529
|
-
|
|
806
|
+
const tableKey = `${assignment.module ?? ""}!${assignment.name}`;
|
|
807
|
+
const table = tables.get(tableKey) ?? {
|
|
808
|
+
name: assignment.name,
|
|
809
|
+
module: assignment.module,
|
|
810
|
+
rows: [],
|
|
811
|
+
};
|
|
812
|
+
if (table.rows.length > 0 && table.rows[0][0].length !== assignment.args.length) {
|
|
530
813
|
throw new TlaConfigError(
|
|
531
|
-
`The operator ${assignment.name} is
|
|
814
|
+
`The arity of the operator ${assignment.name} is inconsistent in the configuration file.`,
|
|
532
815
|
);
|
|
533
816
|
}
|
|
534
|
-
rows.push([assignment.args.map(toValue), toValue(assignment.value)]);
|
|
535
|
-
|
|
536
|
-
});
|
|
537
|
-
operatorConstants.forEach((rows, name) => {
|
|
538
|
-
builtins.set(name, createOperatorConstant(name, rows));
|
|
539
|
-
constants.delete(name);
|
|
817
|
+
table.rows.push([assignment.args.map(toValue), toValue(assignment.value)]);
|
|
818
|
+
tables.set(tableKey, table);
|
|
540
819
|
});
|
|
820
|
+
tables.forEach((table) =>
|
|
821
|
+
getScopedKeys(table).forEach((key) =>
|
|
822
|
+
setOperator(
|
|
823
|
+
key,
|
|
824
|
+
createOperatorConstant(table.name, getKeyArity(key) || table.rows[0][0].length, table.rows),
|
|
825
|
+
),
|
|
826
|
+
),
|
|
827
|
+
);
|
|
541
828
|
const substitutions = new Map(
|
|
542
829
|
config.substitutions.flatMap((substitution) =>
|
|
543
830
|
getScopedKeys(substitution).map((key): [string, string] => [
|
|
@@ -546,8 +833,47 @@ export const createEnvironment = (
|
|
|
546
833
|
]),
|
|
547
834
|
),
|
|
548
835
|
);
|
|
836
|
+
config.substitutions
|
|
837
|
+
.filter((substitution) => substitution.module === undefined)
|
|
838
|
+
.forEach((substitution) => {
|
|
839
|
+
const name = substitution.name;
|
|
840
|
+
const target = substitution.target;
|
|
841
|
+
if (!declaredConstants.includes(name) && !linkedRoot.visible.has(name)) {
|
|
842
|
+
throw new TlaConfigError(
|
|
843
|
+
`In the configuration file, the identifier ${name} does not appear in the specification.`,
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
if (config.substitutions.some((other) => other.name === target)) {
|
|
847
|
+
throw new TlaConfigError(
|
|
848
|
+
`In the configuration file, the identifier ${target} appears\non the right-hand side of a <- after already appearing on the\nleft-hand side of one.`,
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
const targetKey = getRootKey(target);
|
|
852
|
+
const definition = definitions.get(targetKey);
|
|
853
|
+
const isDefined =
|
|
854
|
+
definition !== undefined ||
|
|
855
|
+
builtins.has(targetKey) ||
|
|
856
|
+
constants.has(targetKey) ||
|
|
857
|
+
declaredConstants.includes(target) ||
|
|
858
|
+
variables.includes(target);
|
|
859
|
+
if (!isDefined) {
|
|
860
|
+
throw new TlaConfigError(
|
|
861
|
+
`The configuration file substitutes for ${name} with the undefined identifier ${target}.`,
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
if (
|
|
865
|
+
definition?.kind === "Operator" &&
|
|
866
|
+
definition.params.length !==
|
|
867
|
+
(linkedRoot.constants.find((constant) => constant.name === name)?.arity ??
|
|
868
|
+
linkedRoot.visible.get(name)?.arity)
|
|
869
|
+
) {
|
|
870
|
+
throw new TlaConfigError(
|
|
871
|
+
`The configuration file substitutes for ${name} with ${target} of different number of arguments.`,
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
});
|
|
549
875
|
declaredConstants.forEach((name) => {
|
|
550
|
-
if (!constants.has(name) && !substitutions.has(name) && !
|
|
876
|
+
if (!constants.has(name) && !substitutions.has(name) && !operatorKeys.has(name)) {
|
|
551
877
|
throw new TlaConfigError(`The constant ${name} is not assigned a value by the configuration`);
|
|
552
878
|
}
|
|
553
879
|
});
|
|
@@ -561,12 +887,26 @@ export const createEnvironment = (
|
|
|
561
887
|
variables,
|
|
562
888
|
variableIndex: getVariableIndex(
|
|
563
889
|
variables,
|
|
564
|
-
|
|
890
|
+
linkedList.flatMap((linked) => linked.module.variables.map((variable) => variable.name)),
|
|
565
891
|
),
|
|
566
892
|
definitionValues: new Map(),
|
|
567
893
|
constantLevels: new Map(),
|
|
568
894
|
evaluators: new WeakMap(),
|
|
569
895
|
};
|
|
896
|
+
checkInstances(instanceChecks, (name) => {
|
|
897
|
+
const linked = linkedModules.get(name) ?? nestedModules.get(name) ?? linkedRoot;
|
|
898
|
+
return {
|
|
899
|
+
constants: linked.constants,
|
|
900
|
+
variables: linked.variables,
|
|
901
|
+
definitions: [
|
|
902
|
+
...new Set(
|
|
903
|
+
[...linked.visible.values()].flatMap((symbol) => definitions.get(symbol.key) ?? []),
|
|
904
|
+
),
|
|
905
|
+
],
|
|
906
|
+
assumptions: linked.module.assumptions.map((assumption) => assumption.expression),
|
|
907
|
+
getDefinition: (symbol) => definitions.get(linked.visible.get(symbol)?.key ?? symbol),
|
|
908
|
+
};
|
|
909
|
+
});
|
|
570
910
|
substitutions.forEach((target, name) => {
|
|
571
911
|
const definition = definitions.get(target);
|
|
572
912
|
if (
|
|
@@ -579,5 +919,10 @@ export const createEnvironment = (
|
|
|
579
919
|
);
|
|
580
920
|
}
|
|
581
921
|
});
|
|
582
|
-
return {
|
|
922
|
+
return {
|
|
923
|
+
environment,
|
|
924
|
+
assumptions,
|
|
925
|
+
variableLocations: linkedRoot.variableLocations,
|
|
926
|
+
instanceActions,
|
|
927
|
+
};
|
|
583
928
|
};
|