@hyperscale0/hsx 1.0.341 → 1.0.347
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 +1 -1
- package/bases/cards.hsx +0 -1
- package/bases/collections.hsx +0 -2
- package/bases/escrow.hsx +0 -1
- package/bases/financing.hsx +0 -1
- package/bases/insurance.hsx +0 -1
- package/bases/lending.hsx +0 -3
- package/bases/marketplace.hsx +0 -2
- package/bases/money.hsx +0 -1
- package/bases/reporting.hsx +0 -2
- package/bases/savings.hsx +0 -1
- package/bases/wallet.hsx +0 -1
- package/dist/src/ast.d.ts +57 -7
- package/dist/src/ast.d.ts.map +1 -1
- package/dist/src/ast.js.map +1 -1
- package/dist/src/bases-bundle.js +11 -11
- package/dist/src/bases-bundle.js.map +1 -1
- package/dist/src/catalog-program.d.ts +1 -1
- package/dist/src/catalog-program.d.ts.map +1 -1
- package/dist/src/catalog-program.js +0 -13
- package/dist/src/catalog-program.js.map +1 -1
- package/dist/src/checks.d.ts +60 -0
- package/dist/src/checks.d.ts.map +1 -0
- package/dist/src/checks.js +240 -0
- package/dist/src/checks.js.map +1 -0
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +6 -25
- package/dist/src/cli.js.map +1 -1
- package/dist/src/compile.d.ts +29 -12
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +414 -316
- package/dist/src/compile.js.map +1 -1
- package/dist/src/diagnostics.d.ts +14 -1
- package/dist/src/diagnostics.d.ts.map +1 -1
- package/dist/src/diagnostics.js +31 -0
- package/dist/src/diagnostics.js.map +1 -1
- package/dist/src/examples-bundle.js +15 -15
- package/dist/src/examples-bundle.js.map +1 -1
- package/dist/src/header-source.d.ts +30 -0
- package/dist/src/header-source.d.ts.map +1 -1
- package/dist/src/header-source.js +120 -9
- package/dist/src/header-source.js.map +1 -1
- package/dist/src/headers.d.ts +9 -18
- package/dist/src/headers.d.ts.map +1 -1
- package/dist/src/headers.js +25 -23
- package/dist/src/headers.js.map +1 -1
- package/dist/src/index.d.ts +4 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/keywords.d.ts +2 -4
- package/dist/src/keywords.d.ts.map +1 -1
- package/dist/src/keywords.js +6 -5
- package/dist/src/keywords.js.map +1 -1
- package/dist/src/language.d.ts +3 -4
- package/dist/src/language.d.ts.map +1 -1
- package/dist/src/language.js +123 -60
- package/dist/src/language.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 +3 -5
- package/dist/src/lex.js.map +1 -1
- package/dist/src/parse.d.ts +3 -1
- package/dist/src/parse.d.ts.map +1 -1
- package/dist/src/parse.js +234 -22
- package/dist/src/parse.js.map +1 -1
- package/dist/src/std-bundle.d.ts +2 -1
- package/dist/src/std-bundle.d.ts.map +1 -1
- package/dist/src/std-bundle.js +16 -15
- package/dist/src/std-bundle.js.map +1 -1
- package/dist/src/template-guide.d.ts +3 -9
- package/dist/src/template-guide.d.ts.map +1 -1
- package/dist/src/template-guide.js +16 -23
- package/dist/src/template-guide.js.map +1 -1
- package/dist/src/toolchain.d.ts +23 -0
- package/dist/src/toolchain.d.ts.map +1 -0
- package/dist/src/toolchain.js +29 -0
- package/dist/src/toolchain.js.map +1 -0
- package/docs/README.md +69 -28
- package/examples/camera-rental.hsx +0 -1
- package/examples/cards.hsx +0 -1
- package/examples/collections.hsx +0 -2
- package/examples/escrow.hsx +0 -1
- package/examples/financing.hsx +0 -1
- package/examples/insurance.hsx +0 -2
- package/examples/lending.hsx +0 -3
- package/examples/library.hsx +0 -3
- package/examples/marketplace.hsx +0 -2
- package/examples/money.hsx +0 -1
- package/examples/rental-hire.hsx +0 -1
- package/examples/reporting.hsx +0 -2
- package/examples/savings.hsx +0 -1
- package/examples/serviced.hsx +0 -4
- package/examples/wallet.hsx +0 -1
- package/package.json +4 -4
- package/src/ast.ts +56 -3
- package/src/bases-bundle.ts +11 -11
- package/src/catalog-program.ts +0 -13
- package/src/checks.ts +386 -0
- package/src/cli.ts +6 -25
- package/src/compile.ts +583 -438
- package/src/diagnostics.ts +49 -1
- package/src/examples-bundle.ts +15 -15
- package/src/header-source.ts +187 -11
- package/src/headers.ts +31 -32
- package/src/index.ts +10 -4
- package/src/keywords.ts +6 -5
- package/src/language.ts +153 -68
- package/src/lex.ts +3 -5
- package/src/parse.ts +216 -24
- package/src/std-bundle.ts +17 -15
- package/src/template-guide.ts +17 -34
- package/src/toolchain.ts +51 -0
- package/std/booking.hsx +14 -1
- package/std/collections.hsx +12 -2
- package/std/financing.hsx +10 -16
- package/std/money.hsx +2 -3
- package/std/reporting.hsx +10 -1
- package/dist/src/binding-contract.d.ts +0 -22
- package/dist/src/binding-contract.d.ts.map +0 -1
- package/dist/src/binding-contract.js +0 -80
- package/dist/src/binding-contract.js.map +0 -1
- package/dist/src/std-library.d.ts +0 -5
- package/dist/src/std-library.d.ts.map +0 -1
- package/dist/src/std-library.js +0 -5
- package/dist/src/std-library.js.map +0 -1
- package/src/binding-contract.ts +0 -111
- package/src/std-library.ts +0 -7
package/src/index.ts
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
export {
|
|
2
2
|
compile,
|
|
3
3
|
type CompileDiagnostic,
|
|
4
|
-
type CompileOptions,
|
|
5
4
|
type CompileResult,
|
|
6
5
|
type CompileWarning,
|
|
7
6
|
type CompileOriginMapEntry,
|
|
8
|
-
type
|
|
7
|
+
type CompileTerm,
|
|
8
|
+
type CompileTermOverride,
|
|
9
9
|
} from "./compile.ts";
|
|
10
|
+
export type { CompiledCheck, CompiledCheckStep } from "./checks.ts";
|
|
11
|
+
export {
|
|
12
|
+
defaultToolchain,
|
|
13
|
+
toolchain,
|
|
14
|
+
type AdapterBindingTarget,
|
|
15
|
+
type Toolchain,
|
|
16
|
+
} from "./toolchain.ts";
|
|
10
17
|
export type { ProviderAdapter } from "@hyperscale0/adl";
|
|
11
18
|
export { parseProgram } from "./parse.ts";
|
|
12
19
|
export { lex, KEYWORDS } from "./lex.ts";
|
|
13
20
|
export { format } from "./format.ts";
|
|
14
|
-
export { bundledStandardLibrary, type StandardLibrary } from "./std-library.ts";
|
|
15
21
|
export { buildUdlCostManifest, type UdlCostManifest } from "./cost.ts";
|
|
16
22
|
export type {
|
|
17
23
|
Program,
|
|
@@ -24,7 +30,7 @@ export type {
|
|
|
24
30
|
Diagnostic,
|
|
25
31
|
} from "./ast.ts";
|
|
26
32
|
|
|
27
|
-
export { headerManifest, HEADER_NAMES } from "./headers.ts";
|
|
33
|
+
export { headerManifest, HEADER_NAMES, namedHeaders } from "./headers.ts";
|
|
28
34
|
export {
|
|
29
35
|
templateGuide,
|
|
30
36
|
templateIndex,
|
package/src/keywords.ts
CHANGED
|
@@ -7,7 +7,6 @@ export const KEYWORD_HELP = {
|
|
|
7
7
|
"Product contract",
|
|
8
8
|
],
|
|
9
9
|
header: ["Names a reusable library of instruments."],
|
|
10
|
-
use: ["Makes a header's instruments available to this program."],
|
|
11
10
|
party: [
|
|
12
11
|
"Declares a person, business or staff party. Staff authority requires a permission role.",
|
|
13
12
|
"Parties",
|
|
@@ -31,7 +30,6 @@ export const KEYWORD_HELP = {
|
|
|
31
30
|
"Makes an attached action available under a public name.",
|
|
32
31
|
"Object action bindings",
|
|
33
32
|
],
|
|
34
|
-
hide: ["Removes an action from the program's public actions."],
|
|
35
33
|
as: ["Gives an exposed action its public name."],
|
|
36
34
|
cap: ["Limits a percentage charge to a maximum money amount.", "Capped rate"],
|
|
37
35
|
of: [
|
|
@@ -40,8 +38,8 @@ export const KEYWORD_HELP = {
|
|
|
40
38
|
when: [
|
|
41
39
|
"Includes clauses for a selected enum value or a field present on a bound reference.",
|
|
42
40
|
],
|
|
43
|
-
|
|
44
|
-
"
|
|
41
|
+
checks: [
|
|
42
|
+
"Rules each attachment's tunables must pass, each with its own message and fix.",
|
|
45
43
|
],
|
|
46
44
|
requires: [
|
|
47
45
|
"Rejects an action unless the stated condition holds.",
|
|
@@ -66,7 +64,10 @@ export const KEYWORD_HELP = {
|
|
|
66
64
|
is: ["Selects rules for one named parameter choice."],
|
|
67
65
|
has: ["Selects clauses when a bound reference declares the named field."],
|
|
68
66
|
family: ["Names an instrument family or the family of an evidence check."],
|
|
69
|
-
check: [
|
|
67
|
+
check: [
|
|
68
|
+
"Declares a Build check: customers, steps and the balances they end on. Inside evidence, names the provider check the action requires.",
|
|
69
|
+
"Build checks",
|
|
70
|
+
],
|
|
70
71
|
result: ["Names the required outcome of an evidence check."],
|
|
71
72
|
maxAge: ["Limits how old the required evidence may be."],
|
|
72
73
|
instruction: ["Binds evidence to the captured boundary instruction."],
|
package/src/language.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { Entry, Expr, Span } from "./ast.ts";
|
|
1
|
+
import type { CheckDecl, Entry, Expr, Span } from "./ast.ts";
|
|
2
|
+
import { compile, type CompileTerm } from "./compile.ts";
|
|
2
3
|
import { headerManifest } from "./headers.ts";
|
|
3
4
|
import { KEYWORD_HELP } from "./keywords.ts";
|
|
4
5
|
import { KEYWORDS, scan, type Token } from "./lex.ts";
|
|
5
6
|
import { parseProgram } from "./parse.ts";
|
|
6
|
-
import {
|
|
7
|
-
export type { StandardLibrary } from "./std-library.ts";
|
|
7
|
+
import { defaultToolchain, type Toolchain } from "./toolchain.ts";
|
|
8
8
|
|
|
9
9
|
export type HsxTokenClass =
|
|
10
10
|
| "keyword"
|
|
@@ -44,6 +44,24 @@ export interface HsxHover {
|
|
|
44
44
|
type Help = Omit<HsxHover, "span">;
|
|
45
45
|
type Header = ReturnType<typeof headerManifest>["headers"][number];
|
|
46
46
|
const keywords = new Set<string>(KEYWORDS);
|
|
47
|
+
const CHECK_WORDS = new Set([
|
|
48
|
+
"customer",
|
|
49
|
+
"organization",
|
|
50
|
+
"funded",
|
|
51
|
+
"binds",
|
|
52
|
+
"clock",
|
|
53
|
+
"until",
|
|
54
|
+
"record",
|
|
55
|
+
"close",
|
|
56
|
+
"remember",
|
|
57
|
+
"status",
|
|
58
|
+
"balances",
|
|
59
|
+
"expect",
|
|
60
|
+
"held",
|
|
61
|
+
"pending",
|
|
62
|
+
]);
|
|
63
|
+
const CHECK_HELP =
|
|
64
|
+
"A check step. Promote runs every check in an isolated world and refuses a Build whose check fails.";
|
|
47
65
|
const types = new Set([
|
|
48
66
|
"money",
|
|
49
67
|
"account",
|
|
@@ -59,20 +77,20 @@ const types = new Set([
|
|
|
59
77
|
"list",
|
|
60
78
|
"policy",
|
|
61
79
|
]);
|
|
62
|
-
// Cache by source bytes, not
|
|
80
|
+
// Cache by source bytes, not toolchain identity: callers can edit their own headers.
|
|
63
81
|
const headerCache = new Map<
|
|
64
82
|
string,
|
|
65
83
|
{ source: string; value: Header | undefined }
|
|
66
84
|
>();
|
|
67
|
-
function header(name: string,
|
|
85
|
+
function header(name: string, toolchain: Toolchain): Header | undefined {
|
|
68
86
|
try {
|
|
69
|
-
const source =
|
|
87
|
+
const source = toolchain.std.get(name);
|
|
70
88
|
if (!source) return;
|
|
71
89
|
const cached = headerCache.get(name);
|
|
72
90
|
if (cached?.source === source) return cached.value;
|
|
73
91
|
let value: Header | undefined;
|
|
74
92
|
try {
|
|
75
|
-
value = headerManifest(
|
|
93
|
+
value = headerManifest(new Map([[name, source]]), [name]).headers[0];
|
|
76
94
|
} catch {
|
|
77
95
|
/* Half-written headers have no metadata yet. */
|
|
78
96
|
}
|
|
@@ -105,6 +123,10 @@ function instrumentHelp(
|
|
|
105
123
|
label: a.name,
|
|
106
124
|
value: `${a.summary} Actor: ${a.actor}`,
|
|
107
125
|
})),
|
|
126
|
+
...object.checks.map((check) => ({
|
|
127
|
+
label: "check",
|
|
128
|
+
value: `${check.rule}${check.when ? ` when ${check.when.selector} is ${check.when.is}` : ""}: ${check.message}`,
|
|
129
|
+
})),
|
|
108
130
|
],
|
|
109
131
|
};
|
|
110
132
|
}
|
|
@@ -119,14 +141,26 @@ interface Analysis {
|
|
|
119
141
|
highlights: HsxHighlight[];
|
|
120
142
|
hovers: Map<number, HsxHover>;
|
|
121
143
|
}
|
|
122
|
-
function analyze(source: string,
|
|
144
|
+
function analyze(source: string, toolchain: Toolchain): Analysis {
|
|
123
145
|
const all = scan(source).tokens.filter((t) => t.kind !== "eof");
|
|
124
146
|
const tokens = all.filter((t) => t.kind !== "comment");
|
|
125
147
|
const helps = new Map<number, Help>();
|
|
126
148
|
const classes = new Map<number, HsxTokenClass>();
|
|
127
149
|
const bindings = new Map<string, Binding[]>();
|
|
128
|
-
|
|
129
|
-
const headerHelp =
|
|
150
|
+
// A qualified name such as booking.reservation names its header directly.
|
|
151
|
+
const headerHelp = (value: Header): Help => ({
|
|
152
|
+
kind: "header",
|
|
153
|
+
title: value.name,
|
|
154
|
+
header: value.name,
|
|
155
|
+
summary: value.objects
|
|
156
|
+
.map((o) => o.summary)
|
|
157
|
+
.slice(0, 2)
|
|
158
|
+
.join(" "),
|
|
159
|
+
details: value.objects.map((o) => ({
|
|
160
|
+
label: o.qualifiedName,
|
|
161
|
+
value: o.summary,
|
|
162
|
+
})),
|
|
163
|
+
});
|
|
130
164
|
const whole = { start: 0, end: source.length };
|
|
131
165
|
const text = (span: Span) => source.slice(span.start, span.end);
|
|
132
166
|
const mark = (token: Token | undefined, kind: HsxTokenClass, help?: Help) => {
|
|
@@ -177,31 +211,6 @@ function analyze(source: string, library: StandardLibrary): Analysis {
|
|
|
177
211
|
for (let i = 0; i < tokens.length; i++) {
|
|
178
212
|
const token = tokens[i]!;
|
|
179
213
|
const previous = tokens[i - 1]?.text;
|
|
180
|
-
if (previous === "use") {
|
|
181
|
-
const value = header(token.text, library);
|
|
182
|
-
if (value) imports.set(token.text, value);
|
|
183
|
-
mark(
|
|
184
|
-
token,
|
|
185
|
-
"header",
|
|
186
|
-
value
|
|
187
|
-
? {
|
|
188
|
-
kind: "header",
|
|
189
|
-
title: value.name,
|
|
190
|
-
header: value.name,
|
|
191
|
-
summary: value.objects
|
|
192
|
-
.map((o) => o.summary)
|
|
193
|
-
.slice(0, 2)
|
|
194
|
-
.join(" "),
|
|
195
|
-
details: value.objects.map((o) => ({
|
|
196
|
-
label: o.qualifiedName,
|
|
197
|
-
value: o.summary,
|
|
198
|
-
})),
|
|
199
|
-
}
|
|
200
|
-
: undefined,
|
|
201
|
-
);
|
|
202
|
-
const help = helps.get(token.span.start);
|
|
203
|
-
if (help) headerHelp.set(token.text, help);
|
|
204
|
-
}
|
|
205
214
|
if (
|
|
206
215
|
previous === "program" ||
|
|
207
216
|
previous === "object" ||
|
|
@@ -240,7 +249,6 @@ function analyze(source: string, library: StandardLibrary): Analysis {
|
|
|
240
249
|
previous === "action" ||
|
|
241
250
|
previous === "attach" ||
|
|
242
251
|
previous === "expose" ||
|
|
243
|
-
previous === "hide" ||
|
|
244
252
|
previous === "as"
|
|
245
253
|
)
|
|
246
254
|
mark(
|
|
@@ -266,9 +274,9 @@ function analyze(source: string, library: StandardLibrary): Analysis {
|
|
|
266
274
|
}
|
|
267
275
|
const attachment = (target: string, scope: Span) => {
|
|
268
276
|
const [owner, name] = target.split(".");
|
|
269
|
-
const object =
|
|
270
|
-
|
|
271
|
-
|
|
277
|
+
const object = header(owner ?? "", toolchain)?.objects.find(
|
|
278
|
+
(o) => o.name === name,
|
|
279
|
+
);
|
|
272
280
|
if (!object) return;
|
|
273
281
|
for (const parameter of object.tunables)
|
|
274
282
|
bind(
|
|
@@ -425,6 +433,42 @@ function analyze(source: string, library: StandardLibrary): Analysis {
|
|
|
425
433
|
walk(expr.cap, scope);
|
|
426
434
|
}
|
|
427
435
|
};
|
|
436
|
+
const at = (span: Span) => tokens[atStart.get(span.start) ?? -1];
|
|
437
|
+
// A check's step words are keywords inside the check alone.
|
|
438
|
+
const checkHelp = (check: CheckDecl) => {
|
|
439
|
+
for (const token of tokens)
|
|
440
|
+
if (
|
|
441
|
+
token.span.start > check.span.start &&
|
|
442
|
+
token.span.end < check.span.end &&
|
|
443
|
+
CHECK_WORDS.has(token.text)
|
|
444
|
+
)
|
|
445
|
+
mark(token, "keyword", {
|
|
446
|
+
kind: "keyword",
|
|
447
|
+
title: token.text,
|
|
448
|
+
summary: CHECK_HELP,
|
|
449
|
+
});
|
|
450
|
+
for (const statement of check.statements) {
|
|
451
|
+
if (statement.kind === "customer")
|
|
452
|
+
mark(
|
|
453
|
+
at(statement.id.span),
|
|
454
|
+
"party",
|
|
455
|
+
declared(
|
|
456
|
+
statement.id.name,
|
|
457
|
+
"party",
|
|
458
|
+
check.span,
|
|
459
|
+
statement.id.span,
|
|
460
|
+
`customer ${statement.id.name}`,
|
|
461
|
+
`${statement.title}, a customer of check "${check.name}".`,
|
|
462
|
+
),
|
|
463
|
+
);
|
|
464
|
+
if (statement.kind === "action") {
|
|
465
|
+
mark(at(statement.action.span), "action");
|
|
466
|
+
if (statement.state) mark(at(statement.state.span), "state");
|
|
467
|
+
}
|
|
468
|
+
if (statement.kind === "clock" && statement.until)
|
|
469
|
+
mark(at(statement.until.state.span), "state");
|
|
470
|
+
}
|
|
471
|
+
};
|
|
428
472
|
// The parser owns declarations and scopes. A parse failure leaves lexical context intact.
|
|
429
473
|
try {
|
|
430
474
|
const parsed = parseProgram(source);
|
|
@@ -476,6 +520,7 @@ function analyze(source: string, library: StandardLibrary): Analysis {
|
|
|
476
520
|
walk(decl.body, decl.span);
|
|
477
521
|
}
|
|
478
522
|
}
|
|
523
|
+
for (const check of parsed.program.checks) checkHelp(check);
|
|
479
524
|
} catch {
|
|
480
525
|
/* Arbitrary editor input must not interrupt typing. */
|
|
481
526
|
}
|
|
@@ -486,12 +531,12 @@ function analyze(source: string, library: StandardLibrary): Analysis {
|
|
|
486
531
|
const previous = tokens[i - 1]?.text;
|
|
487
532
|
const next = tokens[i + 1]?.text;
|
|
488
533
|
const owner = previous === "." ? tokens[i - 2]?.text : undefined;
|
|
489
|
-
const imported = owner ?
|
|
534
|
+
const imported = owner ? header(owner, toolchain) : undefined;
|
|
490
535
|
const object = imported?.objects.find((o) => o.name === token.text);
|
|
536
|
+
const named = next === "." ? header(token.text, toolchain) : undefined;
|
|
491
537
|
if (object && owner)
|
|
492
538
|
mark(token, "instrument", instrumentHelp(object, owner));
|
|
493
|
-
else if (
|
|
494
|
-
mark(token, "header", headerHelp.get(token.text));
|
|
539
|
+
else if (named) mark(token, "header", headerHelp(named));
|
|
495
540
|
else if (!helps.has(token.span.start)) {
|
|
496
541
|
const candidates = bindings
|
|
497
542
|
.get(token.text)
|
|
@@ -514,7 +559,6 @@ function analyze(source: string, library: StandardLibrary): Analysis {
|
|
|
514
559
|
!keywords.has(token.text) ||
|
|
515
560
|
previous === "." ||
|
|
516
561
|
previous === "expose" ||
|
|
517
|
-
previous === "hide" ||
|
|
518
562
|
next === ":" ||
|
|
519
563
|
[":", "=", "fee", "moves", "from", "to", "(", ",", "["].includes(
|
|
520
564
|
previous ?? "",
|
|
@@ -583,48 +627,89 @@ function analyze(source: string, library: StandardLibrary): Analysis {
|
|
|
583
627
|
return { highlights, hovers };
|
|
584
628
|
}
|
|
585
629
|
// One editor document is retained. Hovering never reparses the same keystroke.
|
|
586
|
-
let last:
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
// Custom libraries may change without changing identity; only the bundled library is immutable.
|
|
591
|
-
if (
|
|
592
|
-
library === bundledStandardLibrary &&
|
|
593
|
-
last?.source === source &&
|
|
594
|
-
last.library === library
|
|
595
|
-
)
|
|
630
|
+
let last: { source: string; result: Analysis } | undefined;
|
|
631
|
+
function analysis(source: string, toolchain: Toolchain): Analysis {
|
|
632
|
+
// A test toolchain may change its headers in place; the default never does.
|
|
633
|
+
if (toolchain === defaultToolchain && last?.source === source)
|
|
596
634
|
return last.result;
|
|
597
|
-
const result = analyze(source,
|
|
598
|
-
if (
|
|
635
|
+
const result = analyze(source, toolchain);
|
|
636
|
+
if (toolchain === defaultToolchain) last = { source, result };
|
|
599
637
|
return result;
|
|
600
638
|
}
|
|
601
639
|
/** Total, sorted, non-overlapping UTF-16 spans, including incomplete source. */
|
|
602
640
|
export function highlight(
|
|
603
641
|
source: string,
|
|
604
|
-
|
|
642
|
+
toolchain: Toolchain = defaultToolchain,
|
|
605
643
|
): HsxHighlight[] {
|
|
606
|
-
return analysis(source,
|
|
644
|
+
return analysis(source, toolchain).highlights.map((span) => ({ ...span }));
|
|
645
|
+
}
|
|
646
|
+
// The terms of the attach line around an offset, from the last valid compile.
|
|
647
|
+
let compiled:
|
|
648
|
+
| {
|
|
649
|
+
source: string;
|
|
650
|
+
toolchain: Toolchain;
|
|
651
|
+
terms: (offset: number) => CompileTerm[] | undefined;
|
|
652
|
+
}
|
|
653
|
+
| undefined;
|
|
654
|
+
function termsAt(
|
|
655
|
+
source: string,
|
|
656
|
+
offset: number,
|
|
657
|
+
toolchain: Toolchain,
|
|
658
|
+
): CompileTerm[] | undefined {
|
|
659
|
+
if (compiled?.source !== source || compiled.toolchain !== toolchain) {
|
|
660
|
+
const origins = compile(source, toolchain).artifacts?.originMap ?? [];
|
|
661
|
+
compiled = {
|
|
662
|
+
source,
|
|
663
|
+
toolchain,
|
|
664
|
+
// A record shares its attach line's span; the attach comes first.
|
|
665
|
+
terms: (at) =>
|
|
666
|
+
origins.find(
|
|
667
|
+
(entry) =>
|
|
668
|
+
entry.terms && entry.span.start <= at && at < entry.span.end,
|
|
669
|
+
)?.terms,
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
return compiled.terms(offset);
|
|
607
673
|
}
|
|
674
|
+
const inForce = (term: CompileTerm) =>
|
|
675
|
+
`${term.text} (${term.from === "std" ? `${term.source} default` : term.from === "party" ? "the party of that name" : "set by the program"})`;
|
|
608
676
|
/** Offsets use half-open UTF-16 spans. Whitespace and out-of-range offsets return null. */
|
|
609
677
|
export function describe(
|
|
610
678
|
source: string,
|
|
611
679
|
offset: number,
|
|
612
|
-
|
|
680
|
+
toolchain: Toolchain = defaultToolchain,
|
|
613
681
|
): HsxHover | null {
|
|
614
682
|
if (!Number.isInteger(offset) || offset < 0 || offset >= source.length)
|
|
615
683
|
return null;
|
|
616
|
-
const result = analysis(source,
|
|
684
|
+
const result = analysis(source, toolchain);
|
|
617
685
|
const span = result.highlights.find(
|
|
618
686
|
(s) => s.start <= offset && offset < s.end,
|
|
619
687
|
);
|
|
620
688
|
const hover = span && result.hovers.get(span.start);
|
|
621
|
-
return
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
689
|
+
if (!hover) return null;
|
|
690
|
+
const details = hover.details?.map((d) => ({ ...d }));
|
|
691
|
+
// A std tunable and an attach line show the value in force and who set it.
|
|
692
|
+
const terms =
|
|
693
|
+
(hover.kind === "parameter" && hover.header) ||
|
|
694
|
+
(hover.kind === "instrument" &&
|
|
695
|
+
source.lastIndexOf("attach", offset) > source.lastIndexOf("{", offset))
|
|
696
|
+
? termsAt(source, offset, toolchain)
|
|
697
|
+
: undefined;
|
|
698
|
+
const term = terms?.find((t) => t.name === hover.title);
|
|
699
|
+
const added =
|
|
700
|
+
hover.kind === "parameter"
|
|
701
|
+
? term
|
|
702
|
+
? [{ label: "In force", value: inForce(term) }]
|
|
703
|
+
: []
|
|
704
|
+
: (terms ?? []).map((t) => ({
|
|
705
|
+
label: `${t.name} in force`,
|
|
706
|
+
value: inForce(t),
|
|
707
|
+
}));
|
|
708
|
+
return {
|
|
709
|
+
...hover,
|
|
710
|
+
span: { ...hover.span },
|
|
711
|
+
...(details || added.length
|
|
712
|
+
? { details: [...(details ?? []), ...added] }
|
|
713
|
+
: {}),
|
|
714
|
+
};
|
|
630
715
|
}
|
package/src/lex.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { Diagnostic, Span } from "./ast.ts";
|
|
|
2
2
|
export const KEYWORDS = [
|
|
3
3
|
"program",
|
|
4
4
|
"header",
|
|
5
|
-
"use",
|
|
6
5
|
"party",
|
|
7
6
|
"role",
|
|
8
7
|
"currency",
|
|
@@ -11,12 +10,11 @@ export const KEYWORDS = [
|
|
|
11
10
|
"lifecycle",
|
|
12
11
|
"action",
|
|
13
12
|
"expose",
|
|
14
|
-
"hide",
|
|
15
13
|
"as",
|
|
16
14
|
"cap",
|
|
17
15
|
"of",
|
|
18
16
|
"when",
|
|
19
|
-
"
|
|
17
|
+
"checks",
|
|
20
18
|
"requires",
|
|
21
19
|
"invariants",
|
|
22
20
|
"moves",
|
|
@@ -131,10 +129,10 @@ export function scan(
|
|
|
131
129
|
}
|
|
132
130
|
kind = "string";
|
|
133
131
|
text = quoted[0];
|
|
134
|
-
} else if (/^(
|
|
132
|
+
} else if (/^(==|!=|<=|>=|->)/.test(tail)) {
|
|
135
133
|
kind = "punct";
|
|
136
134
|
text = tail.slice(0, 2);
|
|
137
|
-
} else if (/^[{}()[\]
|
|
135
|
+
} else if (/^[{}()[\]:,;=<>?.|+]/.test(tail)) {
|
|
138
136
|
kind = "punct";
|
|
139
137
|
text = tail[0]!;
|
|
140
138
|
} else {
|