@hyperscale0/hsx 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/src/ast.d.ts +17 -2
- package/dist/src/ast.d.ts.map +1 -1
- package/dist/src/ast.js.map +1 -1
- package/dist/src/cli.js +1 -1
- package/dist/src/compile.d.ts +6 -0
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +1194 -97
- package/dist/src/compile.js.map +1 -1
- package/dist/src/cost.d.ts +1 -1
- package/dist/src/cost.d.ts.map +1 -1
- package/dist/src/cost.js +52 -9
- package/dist/src/cost.js.map +1 -1
- package/dist/src/headers.d.ts +2 -2
- package/dist/src/headers.d.ts.map +1 -1
- package/dist/src/headers.js +3 -2
- package/dist/src/headers.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lex.d.ts +1 -1
- package/dist/src/lex.d.ts.map +1 -1
- package/dist/src/lex.js +5 -0
- package/dist/src/lex.js.map +1 -1
- package/dist/src/parse.js +91 -5
- package/dist/src/parse.js.map +1 -1
- package/dist/src/std-bundle.d.ts.map +1 -1
- package/dist/src/std-bundle.js +10 -9
- package/dist/src/std-bundle.js.map +1 -1
- package/dist/src/version.d.ts +2 -2
- package/dist/src/version.js +2 -2
- package/docs/README.md +51 -27
- package/docs/headers.md +43 -40
- package/examples/cost-table.json +40 -324
- package/examples/library.hsx +12 -57
- package/package.json +7 -5
- package/src/ast.ts +11 -1
- package/src/cli.ts +1 -1
- package/src/compile.ts +1630 -114
- package/src/cost.ts +60 -16
- package/src/headers.ts +3 -2
- package/src/index.ts +12 -1
- package/src/lex.ts +5 -0
- package/src/parse.ts +87 -5
- package/src/std-bundle.ts +10 -9
- package/src/version.ts +2 -2
- package/std/approvals.hsx +3 -3
- package/std/collections.hsx +45 -4
- package/std/escrow.hsx +17 -8
- package/std/financing.hsx +292 -42
- package/std/insurance.hsx +4 -5
- package/std/lending.hsx +7 -8
- package/std/marketplace.hsx +90 -6
- package/std/money.hsx +15 -49
- package/std/reporting.hsx +1286 -0
- package/std/travel.hsx +5 -6
package/src/cost.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { resolveField, type UdlDocument } from "@hyperscale0/udl";
|
|
2
2
|
export interface UdlCostManifest {
|
|
3
3
|
actions: Record<
|
|
4
4
|
string,
|
|
@@ -12,21 +12,65 @@ export interface UdlCostManifest {
|
|
|
12
12
|
/** Counts sealed instructions after lowering. Prices belong to the executor's tariff. */
|
|
13
13
|
export function buildUdlCostManifest(document: UdlDocument): UdlCostManifest {
|
|
14
14
|
const actions: UdlCostManifest["actions"] = {};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
15
|
+
const active = new Set<string>();
|
|
16
|
+
const visit = (
|
|
17
|
+
id: string,
|
|
18
|
+
name: string,
|
|
19
|
+
): UdlCostManifest["actions"][string] => {
|
|
20
|
+
const key = `${id}.${name}`;
|
|
21
|
+
if (actions[key]) return actions[key];
|
|
22
|
+
if (active.has(key)) throw new Error(`Invocation cycle at ${key}`);
|
|
23
|
+
const instrument = document.instruments.find((item) => item.id === id);
|
|
24
|
+
const action = instrument?.actions[name];
|
|
25
|
+
if (!instrument || !action) throw new Error(`Unknown invocation ${key}`);
|
|
26
|
+
active.add(key);
|
|
27
|
+
const cost = {
|
|
28
|
+
transfers: action.moves.length,
|
|
29
|
+
accounts:
|
|
30
|
+
name === "create"
|
|
31
|
+
? instrument.fields.filter(
|
|
32
|
+
(field) => field.type === "account" && field.owner === "self",
|
|
33
|
+
).length
|
|
34
|
+
: 0,
|
|
35
|
+
invocations: 0,
|
|
36
|
+
};
|
|
37
|
+
for (const call of action.invoke ?? []) {
|
|
38
|
+
const ref =
|
|
39
|
+
"reference" in call
|
|
40
|
+
? resolveField(document, instrument, call.reference, action.input)
|
|
41
|
+
: undefined;
|
|
42
|
+
const targets =
|
|
43
|
+
"instrument" in call
|
|
44
|
+
? call.instrument
|
|
45
|
+
: "selection" in call
|
|
46
|
+
? call.selection.instrument
|
|
47
|
+
: ref?.type === "ref"
|
|
48
|
+
? ref.target
|
|
49
|
+
: [];
|
|
50
|
+
const children = (typeof targets === "string" ? [targets] : targets).map(
|
|
51
|
+
(target) => visit(target, call.action),
|
|
52
|
+
);
|
|
53
|
+
const count =
|
|
54
|
+
"selection" in call
|
|
55
|
+
? call.selection.limit
|
|
56
|
+
: "instrument" in call
|
|
57
|
+
? (call.range?.maximum ?? 1)
|
|
58
|
+
: 1;
|
|
59
|
+
// A union selects one target per row. Each meter takes its worst case.
|
|
60
|
+
cost.transfers +=
|
|
61
|
+
count * Math.max(0, ...children.map((child) => child.transfers));
|
|
62
|
+
cost.accounts +=
|
|
63
|
+
count * Math.max(0, ...children.map((child) => child.accounts));
|
|
64
|
+
cost.invocations +=
|
|
65
|
+
count *
|
|
66
|
+
(1 + Math.max(0, ...children.map((child) => child.invocations)));
|
|
30
67
|
}
|
|
68
|
+
active.delete(key);
|
|
69
|
+
actions[key] = cost;
|
|
70
|
+
return cost;
|
|
71
|
+
};
|
|
72
|
+
for (const instrument of document.instruments)
|
|
73
|
+
for (const name of Object.keys(instrument.actions))
|
|
74
|
+
visit(instrument.id, name);
|
|
31
75
|
return { actions };
|
|
32
76
|
}
|
package/src/headers.ts
CHANGED
|
@@ -16,6 +16,7 @@ export const HEADER_NAMES = [
|
|
|
16
16
|
"travel",
|
|
17
17
|
"cards",
|
|
18
18
|
"savings",
|
|
19
|
+
"reporting",
|
|
19
20
|
] as const;
|
|
20
21
|
|
|
21
22
|
/** The compiler frontend owns header metadata used by docs and catalogue consumers. */
|
|
@@ -23,7 +24,7 @@ export function headerManifest(
|
|
|
23
24
|
library: StandardLibrary = bundledStandardLibrary,
|
|
24
25
|
) {
|
|
25
26
|
return {
|
|
26
|
-
version:
|
|
27
|
+
version: 4,
|
|
27
28
|
headers: HEADER_NAMES.map((name) => {
|
|
28
29
|
const source = library.source(name);
|
|
29
30
|
if (!source) throw new Error(`Missing standard header ${name}`);
|
|
@@ -110,7 +111,7 @@ export function headerManifest(
|
|
|
110
111
|
requiredImport: `use ${name}`,
|
|
111
112
|
instancePlaceholder: "${instance}",
|
|
112
113
|
source:
|
|
113
|
-
"${instance} = " +
|
|
114
|
+
"attach ${instance} = " +
|
|
114
115
|
`${name}.${decl.name} { ` +
|
|
115
116
|
bindings
|
|
116
117
|
.map((t) => t.name + ": ${" + t.name + "}")
|
package/src/index.ts
CHANGED
|
@@ -4,12 +4,23 @@ export {
|
|
|
4
4
|
type CompileOptions,
|
|
5
5
|
type CompileResult,
|
|
6
6
|
type CompileOriginMapEntry,
|
|
7
|
+
type AdapterBindingTarget,
|
|
7
8
|
} from "./compile.ts";
|
|
9
|
+
export type { ProviderAdapter } from "@hyperscale0/adl";
|
|
8
10
|
export { parseProgram } from "./parse.ts";
|
|
9
11
|
export { lex, KEYWORDS } from "./lex.ts";
|
|
10
12
|
export { format } from "./format.ts";
|
|
11
13
|
export { bundledStandardLibrary, type StandardLibrary } from "./std-library.ts";
|
|
12
14
|
export { buildUdlCostManifest, type UdlCostManifest } from "./cost.ts";
|
|
13
|
-
export type {
|
|
15
|
+
export type {
|
|
16
|
+
Program,
|
|
17
|
+
Decl,
|
|
18
|
+
AssignmentDecl,
|
|
19
|
+
ObjectDecl,
|
|
20
|
+
InstrumentDecl,
|
|
21
|
+
Expr,
|
|
22
|
+
Span,
|
|
23
|
+
Diagnostic,
|
|
24
|
+
} from "./ast.ts";
|
|
14
25
|
|
|
15
26
|
export { headerManifest, HEADER_NAMES } from "./headers.ts";
|
package/src/lex.ts
CHANGED
package/src/parse.ts
CHANGED
|
@@ -172,14 +172,30 @@ class Parser {
|
|
|
172
172
|
});
|
|
173
173
|
continue;
|
|
174
174
|
}
|
|
175
|
+
if (this.eat("object")) {
|
|
176
|
+
const name = this.identifier();
|
|
177
|
+
const title =
|
|
178
|
+
this.peek().kind === "string"
|
|
179
|
+
? (JSON.parse(this.take().text) as string)
|
|
180
|
+
: name;
|
|
181
|
+
const body = this.block();
|
|
182
|
+
program.decls.push({
|
|
183
|
+
kind: "object",
|
|
184
|
+
name,
|
|
185
|
+
title,
|
|
186
|
+
body,
|
|
187
|
+
span: this.span(start),
|
|
188
|
+
});
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
175
191
|
const name = this.identifier();
|
|
176
192
|
this.expect("=");
|
|
177
193
|
const object = this.path();
|
|
178
194
|
const body = this.block();
|
|
179
195
|
program.decls.push({
|
|
180
|
-
kind: "
|
|
196
|
+
kind: "assignment",
|
|
181
197
|
name,
|
|
182
|
-
object,
|
|
198
|
+
target: object,
|
|
183
199
|
body,
|
|
184
200
|
span: this.span(start),
|
|
185
201
|
});
|
|
@@ -194,14 +210,74 @@ class Parser {
|
|
|
194
210
|
if (this.peek().kind === "eof")
|
|
195
211
|
this.fail(`unclosed block, expected ${end}`, `add ${end}`);
|
|
196
212
|
const start = this.peek().span.start;
|
|
213
|
+
if (this.eat("attach")) {
|
|
214
|
+
const name = this.identifier();
|
|
215
|
+
this.expect("=");
|
|
216
|
+
const target = this.path();
|
|
217
|
+
const body = this.block();
|
|
218
|
+
entries.push({
|
|
219
|
+
key: `attach ${name} = ${target}`,
|
|
220
|
+
value: body,
|
|
221
|
+
span: this.span(start),
|
|
222
|
+
});
|
|
223
|
+
this.separators();
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (this.eat("rename")) {
|
|
227
|
+
const body = this.block();
|
|
228
|
+
entries.push({
|
|
229
|
+
key: "rename",
|
|
230
|
+
value: body,
|
|
231
|
+
span: this.span(start),
|
|
232
|
+
});
|
|
233
|
+
this.separators();
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (this.eat("expose")) {
|
|
237
|
+
const action = this.identifier();
|
|
238
|
+
let publicName = action;
|
|
239
|
+
if (this.eat("as")) {
|
|
240
|
+
publicName = this.identifier();
|
|
241
|
+
}
|
|
242
|
+
entries.push({
|
|
243
|
+
key: "expose",
|
|
244
|
+
value: {
|
|
245
|
+
kind: "call",
|
|
246
|
+
name: action,
|
|
247
|
+
args: [{ kind: "name", value: publicName, span: this.span(start) }],
|
|
248
|
+
span: this.span(start),
|
|
249
|
+
},
|
|
250
|
+
span: this.span(start),
|
|
251
|
+
});
|
|
252
|
+
this.separators();
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
197
255
|
let key = this.path();
|
|
256
|
+
if (key === "columns" && !this.at(":")) {
|
|
257
|
+
let value: Expr;
|
|
258
|
+
if (this.at("[")) {
|
|
259
|
+
value = this.atom();
|
|
260
|
+
} else if (this.at("{")) {
|
|
261
|
+
value = this.block();
|
|
262
|
+
} else {
|
|
263
|
+
value = { kind: "list", items: [], span: this.span(start) };
|
|
264
|
+
}
|
|
265
|
+
entries.push({
|
|
266
|
+
key: "columns",
|
|
267
|
+
value,
|
|
268
|
+
span: this.span(start),
|
|
269
|
+
});
|
|
270
|
+
this.separators();
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
198
273
|
if (key === "action" && !this.at(":")) key += " " + this.identifier();
|
|
199
274
|
if (key === "when") {
|
|
200
275
|
const tunable = this.identifier();
|
|
201
|
-
this.
|
|
276
|
+
const relation = this.eat("has") ? "has" : "is";
|
|
277
|
+
if (relation === "is") this.expect("is");
|
|
202
278
|
const choice = this.identifier();
|
|
203
279
|
entries.push({
|
|
204
|
-
key: `when ${tunable}
|
|
280
|
+
key: `when ${tunable} ${relation} ${choice}`,
|
|
205
281
|
value: this.block(),
|
|
206
282
|
span: this.span(start),
|
|
207
283
|
});
|
|
@@ -241,7 +317,8 @@ class Parser {
|
|
|
241
317
|
private operand(): BlockExpr {
|
|
242
318
|
const value = this.atom();
|
|
243
319
|
return this.record({
|
|
244
|
-
[value.kind === "name" &&
|
|
320
|
+
[value.kind === "name" &&
|
|
321
|
+
/^(self|input|party|subject)\./.test(value.value)
|
|
245
322
|
? "field"
|
|
246
323
|
: "literal"]: value,
|
|
247
324
|
});
|
|
@@ -263,6 +340,8 @@ class Parser {
|
|
|
263
340
|
};
|
|
264
341
|
if (this.eat("for")) values.action = this.atom();
|
|
265
342
|
if (this.eat("is")) values.decision = this.atom();
|
|
343
|
+
for (const key of ["protectedRequest", "differentFromInitiator"])
|
|
344
|
+
if (this.eat(key)) values[key] = this.atom();
|
|
266
345
|
return this.record(values);
|
|
267
346
|
}
|
|
268
347
|
if (this.eat("unique")) {
|
|
@@ -315,6 +394,7 @@ class Parser {
|
|
|
315
394
|
this.expect(key);
|
|
316
395
|
values[key] = this.atom();
|
|
317
396
|
}
|
|
397
|
+
if (this.eat("instruction")) values.instruction = this.atom();
|
|
318
398
|
return this.record(values);
|
|
319
399
|
}
|
|
320
400
|
const left = this.operand();
|
|
@@ -360,6 +440,8 @@ class Parser {
|
|
|
360
440
|
}
|
|
361
441
|
for (const key of ["fee", "capture", "key"])
|
|
362
442
|
if (this.eat(key)) values[key] = this.atom();
|
|
443
|
+
if (this.eat("boundary"))
|
|
444
|
+
values.boundary = this.record({ adapter: this.atom() });
|
|
363
445
|
return this.record(values);
|
|
364
446
|
}
|
|
365
447
|
private block(): BlockExpr {
|