@shapeshift-labs/frontier-lang-parser 0.3.58 → 0.3.60
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/dist/index.js +12 -4
- package/dist/type-expressions.js +53 -0
- package/dist/type-parameters.js +53 -0
- package/dist/type-variants.js +2 -2
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { parseRuntimeCapabilityBlock } from './runtime-capability.js';
|
|
|
17
17
|
import { parseNativeSourceBlock } from './source-evidence.js';
|
|
18
18
|
import { parseTargetProjectionMetadata } from './target-projection.js';
|
|
19
19
|
import { parseOptionalTypeExpression, parseTypeExpression } from './type-expressions.js';
|
|
20
|
+
import { readTypeParameterNames, readTypeParameterRecords } from './type-parameters.js';
|
|
20
21
|
import { readVariantPayloadFields } from './type-variants.js';
|
|
21
22
|
import { parseViewBlock } from './view.js';
|
|
22
23
|
import { FrontierSourceBlockKinds, readFrontierSourceBlocks } from './source-syntax-report.js';
|
|
@@ -168,7 +169,17 @@ function parseCapability(block) {
|
|
|
168
169
|
function parseType(block) {
|
|
169
170
|
const name = nameFrom(block.header);
|
|
170
171
|
const alias = /^\s*=\s*([^\n]+)/m.exec(block.body)?.[1]?.trim();
|
|
171
|
-
|
|
172
|
+
const typeParameters = readTypeParameterRecords(block.header);
|
|
173
|
+
return typeNode({
|
|
174
|
+
id: idFrom(block.header, `type_${name}`),
|
|
175
|
+
name,
|
|
176
|
+
parameters: typeParameters?.map((parameter) => parameter.name) ?? readTypeParameterNames(block.header),
|
|
177
|
+
...(typeParameters ? { typeParameters } : {}),
|
|
178
|
+
type: alias ? parseTypeExpression(alias) : undefined,
|
|
179
|
+
fields: readTypeFields(block.body),
|
|
180
|
+
variants: readVariants(block.body),
|
|
181
|
+
invariants: readList('invariants', block.body)
|
|
182
|
+
});
|
|
172
183
|
}
|
|
173
184
|
function parseExtern(block) {
|
|
174
185
|
const name = nameFrom(block.header);
|
|
@@ -281,9 +292,6 @@ function parseSemantic(text) {
|
|
|
281
292
|
if (latticeId) return { kind: 'lattice', latticeId };
|
|
282
293
|
return undefined;
|
|
283
294
|
}
|
|
284
|
-
function readTypeParameters(header) {
|
|
285
|
-
return /<([^>]+)>/.exec(header)?.[1]?.split(',').map((item) => item.trim()).filter(Boolean);
|
|
286
|
-
}
|
|
287
295
|
function readTypeFields(body) {
|
|
288
296
|
const fields = [];
|
|
289
297
|
const re = /^\s*([A-Za-z_$][\w$]*)(?:\s+@id\(\s*["']([^"']+)["']\s*\))?\s*:\s*([^\n]+)/gm;
|
package/dist/type-expressions.js
CHANGED
|
@@ -14,6 +14,8 @@ export function parseTypeExpression(value) {
|
|
|
14
14
|
if (application.name === 'Set' && parsedArgs.length === 1) return { kind: 'set', item: parsedArgs[0] };
|
|
15
15
|
if (application.name === 'List' && parsedArgs.length === 1) return { kind: 'list', item: parsedArgs[0] };
|
|
16
16
|
if (application.name === 'Map' && parsedArgs.length === 2) return { kind: 'map', key: parsedArgs[0], value: parsedArgs[1] };
|
|
17
|
+
if (application.name === 'Record') return readRecordTypeExpression(application.body) ?? { kind: 'ref', name: application.name, args: parsedArgs };
|
|
18
|
+
if (application.name === 'Union') return readUnionTypeExpression(application.body) ?? { kind: 'ref', name: application.name, args: parsedArgs };
|
|
17
19
|
return { kind: 'ref', name: application.name, args: parsedArgs };
|
|
18
20
|
}
|
|
19
21
|
|
|
@@ -31,3 +33,54 @@ function readTypeApplication(text) {
|
|
|
31
33
|
if (depth !== 0) return undefined;
|
|
32
34
|
return { name: match[1], body: text.slice(match[1].length + 1, -1).trim() };
|
|
33
35
|
}
|
|
36
|
+
|
|
37
|
+
function readRecordTypeExpression(body) {
|
|
38
|
+
const fields = [];
|
|
39
|
+
for (const source of splitTopLevelCommaList(body)) {
|
|
40
|
+
const field = readInlineTypeField(source, 'record_field');
|
|
41
|
+
if (!field) return undefined;
|
|
42
|
+
fields.push(field);
|
|
43
|
+
}
|
|
44
|
+
return fields.length ? { kind: 'record', fields } : undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function readUnionTypeExpression(body) {
|
|
48
|
+
const variants = [];
|
|
49
|
+
for (const source of splitTopLevelCommaList(body)) {
|
|
50
|
+
const variant = readInlineTypeVariant(source);
|
|
51
|
+
if (!variant) return undefined;
|
|
52
|
+
variants.push(variant);
|
|
53
|
+
}
|
|
54
|
+
return variants.length ? { kind: 'union', variants } : undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function readInlineTypeVariant(source) {
|
|
58
|
+
const match = /^\s*([A-Za-z_$][\w$]*)(?:\s+@id\(\s*["']([^"']+)["']\s*\))?(?:\((.*)\))?\s*$/.exec(source);
|
|
59
|
+
if (!match) return undefined;
|
|
60
|
+
const payload = match[3]?.trim();
|
|
61
|
+
const fields = [];
|
|
62
|
+
if (payload) {
|
|
63
|
+
for (const fieldSource of splitTopLevelCommaList(payload)) {
|
|
64
|
+
const field = readInlineTypeField(fieldSource, `variant_field_${match[1]}`);
|
|
65
|
+
if (!field) return undefined;
|
|
66
|
+
fields.push(field);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
...(match[2] ? { id: match[2] } : {}),
|
|
71
|
+
name: match[1],
|
|
72
|
+
...(fields.length ? { fields } : {})
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function readInlineTypeField(source, idPrefix) {
|
|
77
|
+
const match = /^\s*([A-Za-z_$][\w$]*)(\?)?(?:\s+@id\(\s*["']([^"']+)["']\s*\))?(\?)?\s*:\s*(.+)\s*$/.exec(source);
|
|
78
|
+
if (!match || !match[5].trim()) return undefined;
|
|
79
|
+
const optional = Boolean(match[2] || match[4]);
|
|
80
|
+
return {
|
|
81
|
+
id: match[3] ?? `${idPrefix}_${match[1]}`,
|
|
82
|
+
name: match[1],
|
|
83
|
+
type: parseTypeExpression(match[5].trim()),
|
|
84
|
+
...(optional ? { optional: true } : {})
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { parseTypeExpression } from './type-expressions.js';
|
|
2
|
+
import { splitTopLevelCommaList } from './type-variants.js';
|
|
3
|
+
|
|
4
|
+
export function readTypeParameterNames(header) {
|
|
5
|
+
return readTypeParameterRecords(header)?.map((parameter) => parameter.name);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function readTypeParameterRecords(header) {
|
|
9
|
+
const source = readTypeParameterSource(header);
|
|
10
|
+
if (!source) return undefined;
|
|
11
|
+
const records = [];
|
|
12
|
+
for (const item of splitTopLevelCommaList(source)) {
|
|
13
|
+
const record = readTypeParameterRecord(item);
|
|
14
|
+
if (!record) return undefined;
|
|
15
|
+
records.push(record);
|
|
16
|
+
}
|
|
17
|
+
return records.length ? records : undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function readTypeParameterRecord(source) {
|
|
21
|
+
const [withoutDefault, defaultSource] = splitTopLevelAssignment(source);
|
|
22
|
+
const match = /^\s*([A-Za-z_$][\w$]*)(?:(?:\s+extends\s+|\s*:\s*)(.+))?\s*$/.exec(withoutDefault);
|
|
23
|
+
if (!match) return undefined;
|
|
24
|
+
return {
|
|
25
|
+
name: match[1],
|
|
26
|
+
...(match[2]?.trim() ? { constraint: parseTypeExpression(match[2].trim()) } : {}),
|
|
27
|
+
...(defaultSource?.trim() ? { default: parseTypeExpression(defaultSource.trim()) } : {})
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function readTypeParameterSource(header) {
|
|
32
|
+
const start = header.indexOf('<');
|
|
33
|
+
if (start < 0) return undefined;
|
|
34
|
+
let depth = 0;
|
|
35
|
+
for (let index = start; index < header.length; index++) {
|
|
36
|
+
const char = header[index];
|
|
37
|
+
if (char === '<') depth++;
|
|
38
|
+
if (char === '>') depth--;
|
|
39
|
+
if (depth === 0) return header.slice(start + 1, index).trim();
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function splitTopLevelAssignment(source) {
|
|
45
|
+
let depth = 0;
|
|
46
|
+
for (let index = 0; index < source.length; index++) {
|
|
47
|
+
const char = source[index];
|
|
48
|
+
if (char === '<') depth++;
|
|
49
|
+
if (char === '>') depth--;
|
|
50
|
+
if (char === '=' && depth === 0) return [source.slice(0, index).trim(), source.slice(index + 1).trim()];
|
|
51
|
+
}
|
|
52
|
+
return [source.trim(), undefined];
|
|
53
|
+
}
|
package/dist/type-variants.js
CHANGED
|
@@ -47,8 +47,8 @@ export function splitTopLevelCommaList(source) {
|
|
|
47
47
|
let start = 0;
|
|
48
48
|
for (let index = 0; index < source.length; index++) {
|
|
49
49
|
const char = source[index];
|
|
50
|
-
if (char === '<') depth++;
|
|
51
|
-
if (char === '>') depth = Math.max(0, depth - 1);
|
|
50
|
+
if (char === '<' || char === '(' || char === '[' || char === '{') depth++;
|
|
51
|
+
if (char === '>' || char === ')' || char === ']' || char === '}') depth = Math.max(0, depth - 1);
|
|
52
52
|
if (char === ',' && depth === 0) {
|
|
53
53
|
parts.push(source.slice(start, index).trim());
|
|
54
54
|
start = index + 1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shapeshift-labs/frontier-lang-parser",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.60",
|
|
4
4
|
"description": "Parser for the first Frontier Lang .frontier syntax slice.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "node scripts/build.mjs",
|
|
25
|
-
"test": "npm run build && node test/smoke.mjs && node test/type-variant-payload-smoke.mjs && node test/type-generic-ref-smoke.mjs && node test/action-body-smoke.mjs && node test/action-structured-literals-smoke.mjs && node test/action-return-smoke.mjs && node test/action-else-smoke.mjs && node test/action-match-smoke.mjs && node test/action-for-in-smoke.mjs && node test/action-repeat-smoke.mjs && node test/action-call-smoke.mjs && node test/target-projection-aggregate-smoke.mjs && node test/conversion-constraint-fields-smoke.mjs && node test/conversion-evidence-smoke.mjs && node test/package-canvas-surface-smoke.mjs && node test/view-render-graph-smoke.mjs && node test/resource-graph-smoke.mjs && node test/interlingua-smoke.mjs && node test/dialect-registry-smoke.mjs",
|
|
25
|
+
"test": "npm run build && node test/smoke.mjs && node test/type-variant-payload-smoke.mjs && node test/type-generic-ref-smoke.mjs && node test/type-parameter-constraints-smoke.mjs && node test/type-structural-expression-smoke.mjs && node test/action-body-smoke.mjs && node test/action-structured-literals-smoke.mjs && node test/action-return-smoke.mjs && node test/action-else-smoke.mjs && node test/action-match-smoke.mjs && node test/action-for-in-smoke.mjs && node test/action-repeat-smoke.mjs && node test/action-call-smoke.mjs && node test/target-projection-aggregate-smoke.mjs && node test/conversion-constraint-fields-smoke.mjs && node test/conversion-evidence-smoke.mjs && node test/package-canvas-surface-smoke.mjs && node test/view-render-graph-smoke.mjs && node test/resource-graph-smoke.mjs && node test/interlingua-smoke.mjs && node test/dialect-registry-smoke.mjs",
|
|
26
26
|
"typecheck": "node ./node_modules/typescript/bin/tsc --noEmit -p test/tsconfig.json",
|
|
27
27
|
"fuzz": "npm run build && node fuzz/smoke.mjs",
|
|
28
28
|
"bench": "npm run build && node bench/smoke.mjs",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"access": "public"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@shapeshift-labs/frontier-lang-kernel": "0.3.
|
|
57
|
+
"@shapeshift-labs/frontier-lang-kernel": "0.3.15"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"typescript": "^5.9.3"
|