@hyperscale0/hsx 2.4.0 → 2.4.1
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/CHANGELOG.md +8 -0
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/typecheck.d.ts.map +1 -1
- package/dist/src/typecheck.js +114 -85
- package/dist/src/typecheck.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/docs/llms-full.txt +2 -2
- package/docs/llms.txt +2 -2
- package/docs/reference/cli.md +2 -2
- package/docs/reference/diagnostics.md +1 -1
- package/docs/reference/grammar.md +1 -1
- package/docs/reference/std/advance.md +1 -1
- package/docs/reference/std/cancellable_booking.md +1 -1
- package/docs/reference/std/captured_payment.md +1 -1
- package/docs/reference/std/conditional_disbursement.md +1 -1
- package/docs/reference/std/credit_facility.md +1 -1
- package/docs/reference/std/held_payment.md +1 -1
- package/docs/reference/std/instant_transfer.md +1 -1
- package/docs/reference/std/metered.md +1 -1
- package/docs/reference/std/pooled_split.md +1 -1
- package/docs/reference/std/premium_forward.md +1 -1
- package/docs/reference/std/reconciled_payout.md +1 -1
- package/docs/reference/std/rotating_pool.md +1 -1
- package/docs/reference/std/scheduled.md +1 -1
- package/docs/reference/std/security_deposit.md +1 -1
- package/docs/reference/std/settlement_batch.md +1 -1
- package/docs/reference/std/swap.md +1 -1
- package/docs/reference/std/threshold_pool.md +1 -1
- package/docs/reference/std/weighted_distribution.md +1 -1
- package/docs/reference/types.md +1 -1
- package/docs/reference/udl-output.md +1 -1
- package/package.json +2 -2
- package/src/typecheck.ts +221 -87
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
The IR format version (`"hsx": 1`, stamped into every compiled document) moves
|
|
8
8
|
independently of the package version.
|
|
9
9
|
|
|
10
|
+
## [2.4.1] - 2026-09-17
|
|
11
|
+
|
|
12
|
+
Pairs with UDL 2.6.0.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- `prefix()` resolves declared instrument `id_prefix` from the catalogue or authored program when known to compilation, falling back to derived initials only when undeclared.
|
|
17
|
+
|
|
10
18
|
## [2.4.0] - 2026-09-17
|
|
11
19
|
|
|
12
20
|
Pairs with UDL 2.6.0.
|
package/dist/src/cli.d.ts
CHANGED
|
@@ -18,6 +18,6 @@ export interface Io {
|
|
|
18
18
|
readonly stdin?: NodeJS.ReadableStream;
|
|
19
19
|
readonly stdout?: NodeJS.WritableStream;
|
|
20
20
|
}
|
|
21
|
-
export declare const USAGE_TEXT = "hsx 2.4.
|
|
21
|
+
export declare const USAGE_TEXT = "hsx 2.4.1, the HSX compiler\n\nUsage:\n hsx check <file.hsx> [--catalog <catalog.udl>] [--strict]\n hsx build <file.hsx> [--catalog <catalog.udl>] [--out <file.json>] [--strict]\n hsx cost <file.hsx> [--catalog <catalog.udl>] [--json] [--out <file.json>] [--strict]\n hsx explain <HSX####>\n hsx format <file.hsx>\n hsx lsp\n hsx --version\n hsx --help\n\nCommands:\n check Compile and report diagnostics. Prints nothing when the program is clean.\n build Compile and write canonical UDL as JSON.\n cost Compile and print the version-pinned cost manifest as a table or JSON.\n explain Print one diagnostic title, fix, and source example.\n format Print the source in the one canonical HSX style.\n lsp Run the language server over stdin and stdout.\n\nOptions:\n --catalog <file> Read the published instrument catalogue as canonical UDL JSON.\n --json Print the cost manifest as JSON instead of a table.\n --out <file> Write build or cost JSON to this path instead of stdout.\n --strict Treat warning-severity diagnostics as failures.\n\nExit codes:\n 0 the program compiled (verdict valid, or warning without --strict)\n 1 the program was refused (verdict invalid, or warning with --strict)\n 2 the command line or the input file could not be used";
|
|
22
22
|
export declare function runCli(argv: readonly string[], io: Io): Promise<number>;
|
|
23
23
|
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typecheck.d.ts","sourceRoot":"","sources":["../../src/typecheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EAEjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAaV,OAAO,EAKR,MAAM,UAAU,CAAC;AASlB,OAAO,KAAK,EACV,kBAAkB,EASnB,MAAM,SAAS,CAAC;AAajB,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;CACzC;AAkCD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,mBAAwB,GAChC,kBAAkB,
|
|
1
|
+
{"version":3,"file":"typecheck.d.ts","sourceRoot":"","sources":["../../src/typecheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EAEjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAaV,OAAO,EAKR,MAAM,UAAU,CAAC;AASlB,OAAO,KAAK,EACV,kBAAkB,EASnB,MAAM,SAAS,CAAC;AAajB,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;CACzC;AAkCD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,mBAAwB,GAChC,kBAAkB,CAufpB"}
|
package/dist/src/typecheck.js
CHANGED
|
@@ -139,15 +139,33 @@ export function checkGeneralProgram(program, options = {}) {
|
|
|
139
139
|
else
|
|
140
140
|
templates.set(decl.name.name, decl);
|
|
141
141
|
}
|
|
142
|
+
const prefixByInstrument = new Map();
|
|
143
|
+
if (options.publishedCatalog) {
|
|
144
|
+
for (const inst of options.publishedCatalog.instruments) {
|
|
145
|
+
if (inst.idPrefix) {
|
|
146
|
+
prefixByInstrument.set(inst.id, inst.idPrefix);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const [name, decl] of templates) {
|
|
151
|
+
const prefix = stringSlot(decl.body, "idPrefix", "id_prefix") ?? prefixFor(name);
|
|
152
|
+
prefixByInstrument.set(name, prefix);
|
|
153
|
+
}
|
|
154
|
+
for (const decl of program.decls) {
|
|
155
|
+
if (decl.kind === "instrument_apply" && decl.metadata) {
|
|
156
|
+
const prefix = stringSlot(decl.metadata, "idPrefix", "id_prefix");
|
|
157
|
+
if (prefix) {
|
|
158
|
+
prefixByInstrument.set(decl.name.name, prefix);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const resolvePrefix = (target) => prefixByInstrument.get(target);
|
|
142
163
|
const concrete = [];
|
|
143
164
|
const reachedPorts = new Set();
|
|
144
165
|
const droppedPorts = new Set();
|
|
145
166
|
const scopedDeclarations = (declarationScope) => {
|
|
146
167
|
const scopedAliases = new Map(aliases);
|
|
147
|
-
const scopedConstants = resolveConstants([
|
|
148
|
-
...program.decls,
|
|
149
|
-
...declarationScope,
|
|
150
|
-
]);
|
|
168
|
+
const scopedConstants = resolveConstants([...program.decls, ...declarationScope], resolvePrefix);
|
|
151
169
|
const scopedParties = new Set(parties);
|
|
152
170
|
const scopedPorts = new Map(ports);
|
|
153
171
|
const scopedTemplates = new Map(templates);
|
|
@@ -160,6 +178,9 @@ export function checkGeneralProgram(program, options = {}) {
|
|
|
160
178
|
scopedPorts.set(local.name.name, local);
|
|
161
179
|
if (local.kind === "instrument") {
|
|
162
180
|
scopedTemplates.set(local.name.name, local);
|
|
181
|
+
const prefix = stringSlot(local.body, "idPrefix", "id_prefix") ??
|
|
182
|
+
prefixFor(local.name.name);
|
|
183
|
+
prefixByInstrument.set(local.name.name, prefix);
|
|
163
184
|
}
|
|
164
185
|
}
|
|
165
186
|
checkPortDeclarations(scopedPorts, scopedParties);
|
|
@@ -189,9 +210,15 @@ export function checkGeneralProgram(program, options = {}) {
|
|
|
189
210
|
values.set(name, reference);
|
|
190
211
|
bindPortCompileValues(values, name, reference, scoped.ports, diagnostics, scoped.aliases, shapes, dependencies);
|
|
191
212
|
}
|
|
192
|
-
const selected = selectCompileTimeRows(decl.body, values, diagnostics, dependencies);
|
|
193
|
-
const body = expandComprehensions(selected, diagnostics, values, dependencies);
|
|
194
|
-
|
|
213
|
+
const selected = selectCompileTimeRows(decl.body, values, diagnostics, dependencies, [], resolvePrefix);
|
|
214
|
+
const body = expandComprehensions(selected, diagnostics, values, dependencies, resolvePrefix);
|
|
215
|
+
const constructed = constructedInstruments(decl.name, body, diagnostics, resolvePrefix);
|
|
216
|
+
for (const candidate of constructed) {
|
|
217
|
+
const prefix = stringSlot(candidate.body, "idPrefix", "id_prefix") ??
|
|
218
|
+
prefixFor(candidate.name.name);
|
|
219
|
+
prefixByInstrument.set(candidate.name.name, prefix);
|
|
220
|
+
}
|
|
221
|
+
concrete.push(...bindActionPorts(constructed, scoped.ports, reachedPorts).map((candidate) => ({
|
|
195
222
|
...candidate,
|
|
196
223
|
aliases: scoped.aliases,
|
|
197
224
|
callee: candidate.name.name,
|
|
@@ -216,13 +243,19 @@ export function checkGeneralProgram(program, options = {}) {
|
|
|
216
243
|
continue;
|
|
217
244
|
}
|
|
218
245
|
const boundPorts = new Map();
|
|
219
|
-
const body = instantiate(template, application, diagnostics, decl.name, scoped.ports, scoped.parties, scoped.aliases, scoped.constants, boundPorts);
|
|
246
|
+
const body = instantiate(template, application, diagnostics, decl.name, scoped.ports, scoped.parties, scoped.aliases, scoped.constants, boundPorts, resolvePrefix);
|
|
220
247
|
if (body) {
|
|
221
248
|
const applicationPorts = new Set();
|
|
222
249
|
const merged = decl.metadata
|
|
223
250
|
? mergeApplicationMetadata(body, decl.metadata, diagnostics)
|
|
224
251
|
: body;
|
|
225
|
-
|
|
252
|
+
const constructed = constructedInstruments(decl.name, merged, diagnostics, resolvePrefix);
|
|
253
|
+
for (const candidate of constructed) {
|
|
254
|
+
const prefix = stringSlot(candidate.body, "idPrefix", "id_prefix") ??
|
|
255
|
+
prefixFor(candidate.name.name);
|
|
256
|
+
prefixByInstrument.set(candidate.name.name, prefix);
|
|
257
|
+
}
|
|
258
|
+
concrete.push(...bindActionPorts(constructed, boundPorts, applicationPorts).map((candidate) => {
|
|
226
259
|
let candidateCallee = callee;
|
|
227
260
|
if (candidate.name.name !== decl.name.name &&
|
|
228
261
|
candidate.name.name.startsWith(`${decl.name.name}_`)) {
|
|
@@ -252,24 +285,11 @@ export function checkGeneralProgram(program, options = {}) {
|
|
|
252
285
|
if (options.publishedCatalog) {
|
|
253
286
|
checkPortCaptureTypes(allocated, options.publishedCatalog, aliases, diagnostics);
|
|
254
287
|
}
|
|
255
|
-
const prefixByInstrument = new Map();
|
|
256
|
-
if (options.publishedCatalog) {
|
|
257
|
-
for (const inst of options.publishedCatalog.instruments) {
|
|
258
|
-
if (inst.idPrefix) {
|
|
259
|
-
prefixByInstrument.set(inst.id, inst.idPrefix);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
for (const [name, decl] of templates) {
|
|
264
|
-
const prefix = stringSlot(decl.body, "idPrefix", "id_prefix") ?? prefixFor(name);
|
|
265
|
-
prefixByInstrument.set(name, prefix);
|
|
266
|
-
}
|
|
267
288
|
for (const candidate of allocated) {
|
|
268
289
|
const prefix = stringSlot(candidate.body, "idPrefix", "id_prefix") ??
|
|
269
290
|
prefixFor(candidate.name.name);
|
|
270
291
|
prefixByInstrument.set(candidate.name.name, prefix);
|
|
271
292
|
}
|
|
272
|
-
const resolvePrefix = (target) => prefixByInstrument.get(target);
|
|
273
293
|
const instruments = [];
|
|
274
294
|
const ids = new Set();
|
|
275
295
|
for (const candidate of allocated) {
|
|
@@ -282,7 +302,7 @@ export function checkGeneralProgram(program, options = {}) {
|
|
|
282
302
|
report("HSX1022", candidate.name.span, `authored instrument ${candidate.name.name} collides with published catalog instrument`, "rename the authored instrument to avoid colliding with the published catalog");
|
|
283
303
|
continue;
|
|
284
304
|
}
|
|
285
|
-
const expandedBody = expandComprehensions(candidate.body, diagnostics);
|
|
305
|
+
const expandedBody = expandComprehensions(candidate.body, diagnostics, new Map(), new Map(), resolvePrefix);
|
|
286
306
|
const checked = checkInstrument(candidate.name, expandedBody, candidate.parties, candidate.ports, candidate.aliases, diagnostics, resolvePrefix);
|
|
287
307
|
if (checked)
|
|
288
308
|
instruments.push(checked);
|
|
@@ -838,8 +858,8 @@ function bindActionPorts(candidates, bindings, reached) {
|
|
|
838
858
|
return { ...candidate, body: { ...candidate.body, entries }, ports };
|
|
839
859
|
});
|
|
840
860
|
}
|
|
841
|
-
function constructedInstruments(rootName, body, diagnostics) {
|
|
842
|
-
const expanded = expandComprehensions(body, diagnostics);
|
|
861
|
+
function constructedInstruments(rootName, body, diagnostics, resolvePrefix) {
|
|
862
|
+
const expanded = expandComprehensions(body, diagnostics, new Map(), new Map(), resolvePrefix);
|
|
843
863
|
const construction = entry(expanded, "instruments");
|
|
844
864
|
const root = {
|
|
845
865
|
body: {
|
|
@@ -984,13 +1004,13 @@ function checkConstants(decls, aliases, diagnostics) {
|
|
|
984
1004
|
validateMoneyLiteral(decl, diagnostics);
|
|
985
1005
|
}
|
|
986
1006
|
}
|
|
987
|
-
function resolveConstants(decls) {
|
|
1007
|
+
function resolveConstants(decls, resolvePrefix) {
|
|
988
1008
|
const constants = new Map(decls
|
|
989
1009
|
.filter((decl) => decl.kind === "const")
|
|
990
1010
|
.map((decl) => [decl.name.name, decl.value]));
|
|
991
1011
|
for (let pass = 0; pass < constants.size; pass += 1) {
|
|
992
1012
|
for (const [name, value] of constants) {
|
|
993
|
-
constants.set(name, substituteExpr(value, constants));
|
|
1013
|
+
constants.set(name, substituteExpr(value, constants, resolvePrefix));
|
|
994
1014
|
}
|
|
995
1015
|
}
|
|
996
1016
|
return constants;
|
|
@@ -1010,7 +1030,7 @@ function validateMoneyLiteral(decl, diagnostics) {
|
|
|
1010
1030
|
span: decl.value.span,
|
|
1011
1031
|
});
|
|
1012
1032
|
}
|
|
1013
|
-
function instantiate(template, application, diagnostics, instrumentName, ports, parties, aliases, constants, boundPorts) {
|
|
1033
|
+
function instantiate(template, application, diagnostics, instrumentName, ports, parties, aliases, constants, boundPorts, resolvePrefix) {
|
|
1014
1034
|
const loweredPortShapes = new Map();
|
|
1015
1035
|
const portDependencies = new Map();
|
|
1016
1036
|
const partyKeyedParameters = partyKeyedBlockParameters(template, aliases);
|
|
@@ -1100,7 +1120,7 @@ function instantiate(template, application, diagnostics, instrumentName, ports,
|
|
|
1100
1120
|
});
|
|
1101
1121
|
continue;
|
|
1102
1122
|
}
|
|
1103
|
-
const expectedExpr = substituteExpr(optionalInner(parameter.type) ?? parameter.type, values);
|
|
1123
|
+
const expectedExpr = substituteExpr(optionalInner(parameter.type) ?? parameter.type, values, resolvePrefix);
|
|
1104
1124
|
const expected = typeOf(expectedExpr, aliases);
|
|
1105
1125
|
const actual = typeOf(value, aliases);
|
|
1106
1126
|
const nonPartyKeys = partyKeyedParameters.get(parameter.name.name);
|
|
@@ -1152,7 +1172,7 @@ function instantiate(template, application, diagnostics, instrumentName, ports,
|
|
|
1152
1172
|
else if (expected.kind !== "party" && value.kind === "ident") {
|
|
1153
1173
|
fieldBindings.set(parameter.name.name, {
|
|
1154
1174
|
name: value,
|
|
1155
|
-
type: substituteExpr(optionalInner(parameter.type) ?? parameter.type, values),
|
|
1175
|
+
type: substituteExpr(optionalInner(parameter.type) ?? parameter.type, values, resolvePrefix),
|
|
1156
1176
|
});
|
|
1157
1177
|
values.set(parameter.name.name, value);
|
|
1158
1178
|
}
|
|
@@ -1165,11 +1185,11 @@ function instantiate(template, application, diagnostics, instrumentName, ports,
|
|
|
1165
1185
|
const port = ports.get(value.name.name);
|
|
1166
1186
|
if (port)
|
|
1167
1187
|
boundPorts.set(parameter.name.name, port);
|
|
1168
|
-
bindPortCompileValues(values, parameter.name.name, value, ports, diagnostics, aliases, loweredPortShapes, portDependencies);
|
|
1188
|
+
bindPortCompileValues(values, parameter.name.name, value, ports, diagnostics, aliases, loweredPortShapes, portDependencies, resolvePrefix);
|
|
1169
1189
|
}
|
|
1170
1190
|
}
|
|
1171
1191
|
checkClaimAmountPortField(resolvedArgs, ports, aliases, diagnostics);
|
|
1172
|
-
const selected = selectCompileTimeRows(template.body, values, diagnostics, portDependencies);
|
|
1192
|
+
const selected = selectCompileTimeRows(template.body, values, diagnostics, portDependencies, [], resolvePrefix);
|
|
1173
1193
|
const dependencyDiagnosticStart = diagnostics.length;
|
|
1174
1194
|
for (const [name, parameter] of missingOptional) {
|
|
1175
1195
|
if (!referencesIdentifier(selected, name, values))
|
|
@@ -1187,7 +1207,7 @@ function instantiate(template, application, diagnostics, instrumentName, ports,
|
|
|
1187
1207
|
}
|
|
1188
1208
|
if (diagnostics.length > dependencyDiagnosticStart)
|
|
1189
1209
|
return undefined;
|
|
1190
|
-
const body = expandComprehensions(selected, diagnostics, values, portDependencies);
|
|
1210
|
+
const body = expandComprehensions(selected, diagnostics, values, portDependencies, resolvePrefix);
|
|
1191
1211
|
const binding = {
|
|
1192
1212
|
key: { kind: "ident", name: "template_binding", span: application.span },
|
|
1193
1213
|
qualifiers: [],
|
|
@@ -1426,7 +1446,7 @@ function shapeTypeText(expr) {
|
|
|
1426
1446
|
}
|
|
1427
1447
|
return nameText(expr);
|
|
1428
1448
|
}
|
|
1429
|
-
function lowerPortShapeField(port, row, aliases, diagnostics) {
|
|
1449
|
+
function lowerPortShapeField(port, row, aliases, diagnostics, resolvePrefix) {
|
|
1430
1450
|
const type = typeOf(row.value, aliases);
|
|
1431
1451
|
if (![
|
|
1432
1452
|
"text",
|
|
@@ -1464,7 +1484,7 @@ function lowerPortShapeField(port, row, aliases, diagnostics) {
|
|
|
1464
1484
|
extras.max_length = 180;
|
|
1465
1485
|
extras.min_length = 1;
|
|
1466
1486
|
if (type.target)
|
|
1467
|
-
extras.pattern = `^${prefixFor(type.target)}_(sandbox|live)_[a-z0-9]{8,64}$`;
|
|
1487
|
+
extras.pattern = `^${resolvePrefix?.(type.target) ?? prefixFor(type.target)}_(sandbox|live)_[a-z0-9]{8,64}$`;
|
|
1468
1488
|
}
|
|
1469
1489
|
else if (type.kind === "account") {
|
|
1470
1490
|
extras.pattern = ACCOUNT_PATTERN;
|
|
@@ -1522,7 +1542,7 @@ function lowerPortShapeField(port, row, aliases, diagnostics) {
|
|
|
1522
1542
|
},
|
|
1523
1543
|
};
|
|
1524
1544
|
}
|
|
1525
|
-
function lowerPortShape(port, rawShape, aliases, diagnostics) {
|
|
1545
|
+
function lowerPortShape(port, rawShape, aliases, diagnostics, resolvePrefix) {
|
|
1526
1546
|
if (rawShape.kind !== "block") {
|
|
1527
1547
|
diagnostics.push({
|
|
1528
1548
|
code: "HSX1025",
|
|
@@ -1547,7 +1567,7 @@ function lowerPortShape(port, rawShape, aliases, diagnostics) {
|
|
|
1547
1567
|
continue;
|
|
1548
1568
|
}
|
|
1549
1569
|
names.add(row.key.name);
|
|
1550
|
-
const lowered = lowerPortShapeField(port, row, aliases, diagnostics);
|
|
1570
|
+
const lowered = lowerPortShapeField(port, row, aliases, diagnostics, resolvePrefix);
|
|
1551
1571
|
if (lowered)
|
|
1552
1572
|
entries.push(lowered);
|
|
1553
1573
|
}
|
|
@@ -1631,7 +1651,7 @@ function checkClaimAmountPortField(resolvedArgs, ports, aliases, diagnostics) {
|
|
|
1631
1651
|
}
|
|
1632
1652
|
}
|
|
1633
1653
|
}
|
|
1634
|
-
function bindPortCompileValues(values, binding, value, ports, diagnostics, aliases = new Map(), loweredPortShapes = new Map(), dependencies = new Map()) {
|
|
1654
|
+
function bindPortCompileValues(values, binding, value, ports, diagnostics, aliases = new Map(), loweredPortShapes = new Map(), dependencies = new Map(), resolvePrefix) {
|
|
1635
1655
|
const port = ports.get(value.name.name);
|
|
1636
1656
|
if (!port) {
|
|
1637
1657
|
diagnostics.push({
|
|
@@ -1655,7 +1675,7 @@ function bindPortCompileValues(values, binding, value, ports, diagnostics, alias
|
|
|
1655
1675
|
span: port.body.span,
|
|
1656
1676
|
};
|
|
1657
1677
|
const shapeDiagnostics = [];
|
|
1658
|
-
shape = lowerPortShape(port, rawShape, aliases, shapeDiagnostics);
|
|
1678
|
+
shape = lowerPortShape(port, rawShape, aliases, shapeDiagnostics, resolvePrefix);
|
|
1659
1679
|
for (const diagnostic of shapeDiagnostics) {
|
|
1660
1680
|
if (!diagnostics.some((prior) => prior.code === diagnostic.code &&
|
|
1661
1681
|
prior.span === diagnostic.span &&
|
|
@@ -1679,7 +1699,7 @@ function bindPortCompileValues(values, binding, value, ports, diagnostics, alias
|
|
|
1679
1699
|
if (value.deadline)
|
|
1680
1700
|
values.set(`${binding}_deadline`, value.deadline);
|
|
1681
1701
|
}
|
|
1682
|
-
function substituteExpr(expr, values) {
|
|
1702
|
+
function substituteExpr(expr, values, resolvePrefix) {
|
|
1683
1703
|
if (expr.kind === "ident") {
|
|
1684
1704
|
return values.get(expr.name) ?? substituteName(expr, values);
|
|
1685
1705
|
}
|
|
@@ -1717,7 +1737,7 @@ function substituteExpr(expr, values) {
|
|
|
1717
1737
|
? {
|
|
1718
1738
|
iteration: {
|
|
1719
1739
|
...entry.iteration,
|
|
1720
|
-
bound: substituteExpr(entry.iteration.bound, values),
|
|
1740
|
+
bound: substituteExpr(entry.iteration.bound, values, resolvePrefix),
|
|
1721
1741
|
},
|
|
1722
1742
|
}
|
|
1723
1743
|
: {}),
|
|
@@ -1734,7 +1754,7 @@ function substituteExpr(expr, values) {
|
|
|
1734
1754
|
? nameFromValue(qualifier, value)
|
|
1735
1755
|
: substituteName(qualifier, nestedValues);
|
|
1736
1756
|
}),
|
|
1737
|
-
value: substituteExpr(entry.value, nestedValues),
|
|
1757
|
+
value: substituteExpr(entry.value, nestedValues, resolvePrefix),
|
|
1738
1758
|
};
|
|
1739
1759
|
}),
|
|
1740
1760
|
};
|
|
@@ -1742,20 +1762,20 @@ function substituteExpr(expr, values) {
|
|
|
1742
1762
|
if (expr.kind === "list") {
|
|
1743
1763
|
return {
|
|
1744
1764
|
...expr,
|
|
1745
|
-
items: expr.items.map((item) => substituteExpr(item, values)),
|
|
1765
|
+
items: expr.items.map((item) => substituteExpr(item, values, resolvePrefix)),
|
|
1746
1766
|
};
|
|
1747
1767
|
}
|
|
1748
1768
|
if (expr.kind === "type_apply") {
|
|
1749
1769
|
return {
|
|
1750
1770
|
...expr,
|
|
1751
|
-
args: expr.args.map((arg) => substituteExpr(arg, values)),
|
|
1771
|
+
args: expr.args.map((arg) => substituteExpr(arg, values, resolvePrefix)),
|
|
1752
1772
|
};
|
|
1753
1773
|
}
|
|
1754
1774
|
if (expr.kind === "call") {
|
|
1755
1775
|
const hasUnbound = expr.args.some((arg) => hasUnboundCompileIdentifier(arg, values));
|
|
1756
1776
|
const substituted = {
|
|
1757
1777
|
...expr,
|
|
1758
|
-
args: expr.args.map((arg) => substituteCompileArgument(arg, values)),
|
|
1778
|
+
args: expr.args.map((arg) => substituteCompileArgument(arg, values, resolvePrefix)),
|
|
1759
1779
|
};
|
|
1760
1780
|
const structural = new Set([
|
|
1761
1781
|
"at",
|
|
@@ -1764,30 +1784,35 @@ function substituteExpr(expr, values) {
|
|
|
1764
1784
|
"keys_except",
|
|
1765
1785
|
"kind",
|
|
1766
1786
|
"len",
|
|
1787
|
+
"prefix",
|
|
1767
1788
|
"values",
|
|
1768
1789
|
]).has(expr.callee.name);
|
|
1769
1790
|
return hasUnbound && !structural
|
|
1770
1791
|
? substituted
|
|
1771
|
-
: (evaluateCompileTimeCall(substituted, !hasUnbound) ??
|
|
1792
|
+
: (evaluateCompileTimeCall(substituted, !hasUnbound, resolvePrefix) ??
|
|
1793
|
+
substituted);
|
|
1772
1794
|
}
|
|
1773
1795
|
if (expr.kind === "apply") {
|
|
1774
1796
|
return {
|
|
1775
1797
|
...expr,
|
|
1776
|
-
args: expr.args.map((arg) => substituteExpr(arg, values)),
|
|
1777
|
-
typeArgs: expr.typeArgs.map((arg) => substituteExpr(arg, values)),
|
|
1798
|
+
args: expr.args.map((arg) => substituteExpr(arg, values, resolvePrefix)),
|
|
1799
|
+
typeArgs: expr.typeArgs.map((arg) => substituteExpr(arg, values, resolvePrefix)),
|
|
1778
1800
|
};
|
|
1779
1801
|
}
|
|
1780
1802
|
if (expr.kind === "binding") {
|
|
1781
|
-
return { ...expr, type: substituteExpr(expr.type, values) };
|
|
1803
|
+
return { ...expr, type: substituteExpr(expr.type, values, resolvePrefix) };
|
|
1782
1804
|
}
|
|
1783
1805
|
if (expr.kind === "decided_amount") {
|
|
1784
|
-
return {
|
|
1806
|
+
return {
|
|
1807
|
+
...expr,
|
|
1808
|
+
body: substituteExpr(expr.body, values, resolvePrefix),
|
|
1809
|
+
};
|
|
1785
1810
|
}
|
|
1786
1811
|
return expr;
|
|
1787
1812
|
}
|
|
1788
|
-
function substituteCompileArgument(expr, values) {
|
|
1813
|
+
function substituteCompileArgument(expr, values, resolvePrefix) {
|
|
1789
1814
|
if (expr.kind !== "ident")
|
|
1790
|
-
return substituteExpr(expr, values);
|
|
1815
|
+
return substituteExpr(expr, values, resolvePrefix);
|
|
1791
1816
|
const value = values.get(expr.name);
|
|
1792
1817
|
if (!value)
|
|
1793
1818
|
return expr;
|
|
@@ -1920,7 +1945,7 @@ function expressionPorts(value, dependencies) {
|
|
|
1920
1945
|
}
|
|
1921
1946
|
return [...found];
|
|
1922
1947
|
}
|
|
1923
|
-
function selectCompileTimeRows(block, values, diagnostics, dependencies = new Map(), controls = []) {
|
|
1948
|
+
function selectCompileTimeRows(block, values, diagnostics, dependencies = new Map(), controls = [], resolvePrefix) {
|
|
1924
1949
|
const entries = [];
|
|
1925
1950
|
const locals = new Map(values);
|
|
1926
1951
|
const localDependencies = new Map(dependencies);
|
|
@@ -1929,13 +1954,13 @@ function selectCompileTimeRows(block, values, diagnostics, dependencies = new Ma
|
|
|
1929
1954
|
const binding = row.qualifiers[0];
|
|
1930
1955
|
if (binding) {
|
|
1931
1956
|
localDependencies.set(binding.name, expressionPorts(row.value, localDependencies));
|
|
1932
|
-
locals.set(binding.name, substituteExpr(row.value, locals));
|
|
1957
|
+
locals.set(binding.name, substituteExpr(row.value, locals, resolvePrefix));
|
|
1933
1958
|
}
|
|
1934
1959
|
entries.push(row);
|
|
1935
1960
|
continue;
|
|
1936
1961
|
}
|
|
1937
1962
|
if (row.key.name === "unsupported") {
|
|
1938
|
-
const value = substituteExpr(row.value, locals);
|
|
1963
|
+
const value = substituteExpr(row.value, locals, resolvePrefix);
|
|
1939
1964
|
if (value.kind !== "block") {
|
|
1940
1965
|
diagnostics.push({
|
|
1941
1966
|
code: "HSX1405",
|
|
@@ -1965,7 +1990,7 @@ function selectCompileTimeRows(block, values, diagnostics, dependencies = new Ma
|
|
|
1965
1990
|
row.key.name !== "when_not" &&
|
|
1966
1991
|
row.key.name !== "when_eq") {
|
|
1967
1992
|
const value = row.value.kind === "block" && !row.iteration
|
|
1968
|
-
? selectCompileTimeRows(row.value, locals, diagnostics, localDependencies, controls)
|
|
1993
|
+
? selectCompileTimeRows(row.value, locals, diagnostics, localDependencies, controls, resolvePrefix)
|
|
1969
1994
|
: row.value;
|
|
1970
1995
|
const conditionPorts = row.key.name === "action"
|
|
1971
1996
|
? [
|
|
@@ -2022,7 +2047,7 @@ function selectCompileTimeRows(block, values, diagnostics, dependencies = new Ma
|
|
|
2022
2047
|
...controls,
|
|
2023
2048
|
...(subject ? expressionPorts(subject, localDependencies) : []),
|
|
2024
2049
|
]),
|
|
2025
|
-
]).entries);
|
|
2050
|
+
], resolvePrefix).entries);
|
|
2026
2051
|
}
|
|
2027
2052
|
}
|
|
2028
2053
|
return { ...block, entries };
|
|
@@ -2042,7 +2067,7 @@ function compileTimeTruthy(value) {
|
|
|
2042
2067
|
return value.entries.length > 0;
|
|
2043
2068
|
return true;
|
|
2044
2069
|
}
|
|
2045
|
-
function evaluateCompileTimeCall(expr, resolveMissing = true) {
|
|
2070
|
+
function evaluateCompileTimeCall(expr, resolveMissing = true, resolvePrefix) {
|
|
2046
2071
|
const [first, second, third, fourth] = expr.args;
|
|
2047
2072
|
const number = (value) => {
|
|
2048
2073
|
if (value?.kind === "percent")
|
|
@@ -2226,7 +2251,9 @@ function evaluateCompileTimeCall(expr, resolveMissing = true) {
|
|
|
2226
2251
|
case "words":
|
|
2227
2252
|
return first ? text(nameText(first).replaceAll("_", " ")) : undefined;
|
|
2228
2253
|
case "prefix":
|
|
2229
|
-
return first
|
|
2254
|
+
return first
|
|
2255
|
+
? text(resolvePrefix?.(nameText(first)) ?? prefixFor(nameText(first)))
|
|
2256
|
+
: undefined;
|
|
2230
2257
|
case "owner":
|
|
2231
2258
|
return first?.kind === "settlement_ref"
|
|
2232
2259
|
? text(first.owner.name)
|
|
@@ -2293,7 +2320,7 @@ function nameText(value) {
|
|
|
2293
2320
|
return `${value.owner.name}.${value.member.name}`;
|
|
2294
2321
|
return "invalid_compile_time_name";
|
|
2295
2322
|
}
|
|
2296
|
-
function expandComprehensions(block, diagnostics, values = new Map(), dependencies = new Map()) {
|
|
2323
|
+
function expandComprehensions(block, diagnostics, values = new Map(), dependencies = new Map(), resolvePrefix) {
|
|
2297
2324
|
const budget = { used: 0 };
|
|
2298
2325
|
const expand = (current, inherited = new Map(), inheritedDependencies = dependencies) => {
|
|
2299
2326
|
const entries = [];
|
|
@@ -2313,7 +2340,7 @@ function expandComprehensions(block, diagnostics, values = new Map(), dependenci
|
|
|
2313
2340
|
continue;
|
|
2314
2341
|
}
|
|
2315
2342
|
localDependencies.set(binding.name, expressionPorts(row.value, localDependencies));
|
|
2316
|
-
locals.set(binding.name, substituteExpr(row.value, locals));
|
|
2343
|
+
locals.set(binding.name, substituteExpr(row.value, locals, resolvePrefix));
|
|
2317
2344
|
continue;
|
|
2318
2345
|
}
|
|
2319
2346
|
if (row.key.name === "when" ||
|
|
@@ -2348,7 +2375,7 @@ function expandComprehensions(block, diagnostics, values = new Map(), dependenci
|
|
|
2348
2375
|
? nameFromValue(qualifier, value)
|
|
2349
2376
|
: substituteName(qualifier, locals);
|
|
2350
2377
|
}),
|
|
2351
|
-
value: substituteExpr(row.value, locals),
|
|
2378
|
+
value: substituteExpr(row.value, locals, resolvePrefix),
|
|
2352
2379
|
};
|
|
2353
2380
|
entries.push({
|
|
2354
2381
|
...substituted,
|
|
@@ -2360,8 +2387,8 @@ function expandComprehensions(block, diagnostics, values = new Map(), dependenci
|
|
|
2360
2387
|
}
|
|
2361
2388
|
if (row.value.kind !== "block")
|
|
2362
2389
|
continue;
|
|
2363
|
-
const bound = substituteExpr(row.iteration.bound, locals);
|
|
2364
|
-
const values = finiteIterationValues(bound);
|
|
2390
|
+
const bound = substituteExpr(row.iteration.bound, locals, resolvePrefix);
|
|
2391
|
+
const values = finiteIterationValues(bound, resolvePrefix);
|
|
2365
2392
|
if (!values) {
|
|
2366
2393
|
diagnostics.push({
|
|
2367
2394
|
code: "HSX1403",
|
|
@@ -2388,7 +2415,7 @@ function expandComprehensions(block, diagnostics, values = new Map(), dependenci
|
|
|
2388
2415
|
...locals,
|
|
2389
2416
|
[row.iteration.binding.name, value],
|
|
2390
2417
|
]);
|
|
2391
|
-
const body = selectCompileTimeRows(row.value, substitutions, diagnostics, localDependencies, row.conditionPorts);
|
|
2418
|
+
const body = selectCompileTimeRows(row.value, substitutions, diagnostics, localDependencies, row.conditionPorts, resolvePrefix);
|
|
2392
2419
|
entries.push(...expand(body, substitutions, localDependencies).entries);
|
|
2393
2420
|
}
|
|
2394
2421
|
}
|
|
@@ -2396,10 +2423,12 @@ function expandComprehensions(block, diagnostics, values = new Map(), dependenci
|
|
|
2396
2423
|
};
|
|
2397
2424
|
return expand(block, values);
|
|
2398
2425
|
}
|
|
2399
|
-
function finiteIterationValues(bound) {
|
|
2426
|
+
function finiteIterationValues(bound, resolvePrefix) {
|
|
2400
2427
|
if (bound.kind === "call") {
|
|
2401
|
-
const evaluated = evaluateCompileTimeCall(bound);
|
|
2402
|
-
return evaluated
|
|
2428
|
+
const evaluated = evaluateCompileTimeCall(bound, true, resolvePrefix);
|
|
2429
|
+
return evaluated
|
|
2430
|
+
? finiteIterationValues(evaluated, resolvePrefix)
|
|
2431
|
+
: undefined;
|
|
2403
2432
|
}
|
|
2404
2433
|
if (bound.kind === "list")
|
|
2405
2434
|
return bound.items;
|
|
@@ -2609,7 +2638,7 @@ function checkInstrument(name, body, parties, ports, aliases, diagnostics, resol
|
|
|
2609
2638
|
if (!actionName || candidate.value.kind !== "block")
|
|
2610
2639
|
return [];
|
|
2611
2640
|
return [
|
|
2612
|
-
checkAction(actionName, candidate.value, fields, name.name, endpointFields, holdDestinations, diagnostics),
|
|
2641
|
+
checkAction(actionName, candidate.value, fields, name.name, endpointFields, holdDestinations, diagnostics, resolvePrefix),
|
|
2613
2642
|
];
|
|
2614
2643
|
})
|
|
2615
2644
|
.map((action) => {
|
|
@@ -2888,7 +2917,7 @@ function lowerField(row, aliases, diagnostics, resolvePrefix) {
|
|
|
2888
2917
|
extra = blockToObject({
|
|
2889
2918
|
...row.value,
|
|
2890
2919
|
entries: row.value.entries.filter((item) => !["type", "description", "desc", "optional", "allow_zero"].includes(item.key.name)),
|
|
2891
|
-
}, new Map(), diagnostics);
|
|
2920
|
+
}, new Map(), diagnostics, false, resolvePrefix);
|
|
2892
2921
|
}
|
|
2893
2922
|
const type = typeOf(typeExpr, aliases);
|
|
2894
2923
|
// Diagnostics point at the field's own type expression, not at an alias
|
|
@@ -3030,7 +3059,7 @@ function checkLifecycle(instrument, block, actions, diagnostics) {
|
|
|
3030
3059
|
}
|
|
3031
3060
|
return { parked, value: { initial, states, transitions } };
|
|
3032
3061
|
}
|
|
3033
|
-
function checkAction(name, body, fields, instrumentId, endpointFields, holdDestinations, diagnostics) {
|
|
3062
|
+
function checkAction(name, body, fields, instrumentId, endpointFields, holdDestinations, diagnostics, resolvePrefix) {
|
|
3034
3063
|
const slots = {};
|
|
3035
3064
|
let omitsPublicAction = false;
|
|
3036
3065
|
const fieldNames = new Set(fields.map((field) => field.name));
|
|
@@ -3076,7 +3105,7 @@ function checkAction(name, body, fields, instrumentId, endpointFields, holdDesti
|
|
|
3076
3105
|
});
|
|
3077
3106
|
}
|
|
3078
3107
|
}
|
|
3079
|
-
const rawValue = exprToJsonForUdlSlot(row.value, definition.target, diagnostics);
|
|
3108
|
+
const rawValue = exprToJsonForUdlSlot(row.value, definition.target, diagnostics, resolvePrefix);
|
|
3080
3109
|
const moveOffset = Array.isArray(slots.moves) ? slots.moves.length : 0;
|
|
3081
3110
|
const value = definition.target === "moves"
|
|
3082
3111
|
? normalizeMoves(rawValue, name.name, instrumentId, fields, endpointFields, holdDestinations, diagnostics, row.span, moveOffset)
|
|
@@ -3788,12 +3817,12 @@ function stringSlot(block, ...names) {
|
|
|
3788
3817
|
return found.name;
|
|
3789
3818
|
return undefined;
|
|
3790
3819
|
}
|
|
3791
|
-
function blockToObject(block, substitutions, diagnostics, literalKeys = false) {
|
|
3820
|
+
function blockToObject(block, substitutions, diagnostics, literalKeys = false, resolvePrefix) {
|
|
3792
3821
|
if (!block)
|
|
3793
3822
|
return {};
|
|
3794
3823
|
const result = {};
|
|
3795
3824
|
for (const row of block.entries) {
|
|
3796
|
-
const value = substituteExpr(row.value, substitutions);
|
|
3825
|
+
const value = substituteExpr(row.value, substitutions, resolvePrefix);
|
|
3797
3826
|
if (twoArgumentMoneyCall(value)) {
|
|
3798
3827
|
diagnostics.push({
|
|
3799
3828
|
code: "HSX1104",
|
|
@@ -3805,11 +3834,11 @@ function blockToObject(block, substitutions, diagnostics, literalKeys = false) {
|
|
|
3805
3834
|
continue;
|
|
3806
3835
|
}
|
|
3807
3836
|
result[literalKeys || row.key.quoted ? row.key.name : camel(row.key.name)] =
|
|
3808
|
-
exprToJson(value, diagnostics, literalKeys);
|
|
3837
|
+
exprToJson(value, diagnostics, literalKeys, resolvePrefix);
|
|
3809
3838
|
}
|
|
3810
3839
|
return result;
|
|
3811
3840
|
}
|
|
3812
|
-
function exprToJsonForUdlSlot(expr, slot, diagnostics) {
|
|
3841
|
+
function exprToJsonForUdlSlot(expr, slot, diagnostics, resolvePrefix) {
|
|
3813
3842
|
if (twoArgumentMoneyCall(expr)) {
|
|
3814
3843
|
diagnostics.push({
|
|
3815
3844
|
code: "HSX1104",
|
|
@@ -3822,16 +3851,16 @@ function exprToJsonForUdlSlot(expr, slot, diagnostics) {
|
|
|
3822
3851
|
if (slot === "callerParkedStates" && expr.kind === "block") {
|
|
3823
3852
|
return Object.fromEntries(expr.entries.map((row) => [
|
|
3824
3853
|
row.key.name,
|
|
3825
|
-
exprToJson(row.value, diagnostics),
|
|
3854
|
+
exprToJson(row.value, diagnostics, false, resolvePrefix),
|
|
3826
3855
|
]));
|
|
3827
3856
|
}
|
|
3828
3857
|
// Declaration maps retain their authored keys; field-spelling aliases still normalize.
|
|
3829
3858
|
const literalKeys = udlClauseVocabulary.some((clause) => clause.target === slot &&
|
|
3830
3859
|
"literalKeys" in clause &&
|
|
3831
3860
|
clause.literalKeys === true);
|
|
3832
|
-
return exprToJson(expr, diagnostics, literalKeys);
|
|
3861
|
+
return exprToJson(expr, diagnostics, literalKeys, resolvePrefix);
|
|
3833
3862
|
}
|
|
3834
|
-
function exprToJson(expr, diagnostics, literalKeys = false) {
|
|
3863
|
+
function exprToJson(expr, diagnostics, literalKeys = false, resolvePrefix) {
|
|
3835
3864
|
switch (expr.kind) {
|
|
3836
3865
|
case "boolean":
|
|
3837
3866
|
return expr.value;
|
|
@@ -3873,17 +3902,17 @@ function exprToJson(expr, diagnostics, literalKeys = false) {
|
|
|
3873
3902
|
case "settlement_ref":
|
|
3874
3903
|
return `${expr.owner.name}.${expr.member.name}`;
|
|
3875
3904
|
case "list":
|
|
3876
|
-
return expr.items.map((item) => exprToJson(item, diagnostics, literalKeys));
|
|
3905
|
+
return expr.items.map((item) => exprToJson(item, diagnostics, literalKeys, resolvePrefix));
|
|
3877
3906
|
case "block":
|
|
3878
|
-
return blockToObject(expr, new Map(), diagnostics, literalKeys);
|
|
3907
|
+
return blockToObject(expr, new Map(), diagnostics, literalKeys, resolvePrefix);
|
|
3879
3908
|
case "call":
|
|
3880
|
-
return `${expr.callee.name}(${expr.args.map((arg) => String(exprToJson(arg, diagnostics))).join(",")})`;
|
|
3909
|
+
return `${expr.callee.name}(${expr.args.map((arg) => String(exprToJson(arg, diagnostics, false, resolvePrefix))).join(",")})`;
|
|
3881
3910
|
case "type_apply":
|
|
3882
|
-
return `${expr.callee.name}<${expr.args.map((arg) => String(exprToJson(arg, diagnostics))).join(",")}>`;
|
|
3911
|
+
return `${expr.callee.name}<${expr.args.map((arg) => String(exprToJson(arg, diagnostics, false, resolvePrefix))).join(",")}>`;
|
|
3883
3912
|
case "binding":
|
|
3884
|
-
return exprToJson(expr.type, diagnostics);
|
|
3913
|
+
return exprToJson(expr.type, diagnostics, false, resolvePrefix);
|
|
3885
3914
|
case "decided_amount":
|
|
3886
|
-
return blockToObject(expr.body, new Map(), diagnostics);
|
|
3915
|
+
return blockToObject(expr.body, new Map(), diagnostics, false, resolvePrefix);
|
|
3887
3916
|
case "port_ref":
|
|
3888
3917
|
return expr.name.name;
|
|
3889
3918
|
case "apply":
|