@shapeshift-labs/frontier-lang-parser 0.3.20 → 0.3.21
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 +21 -0
- package/dist/index.js +5 -2
- package/dist/interlingua.js +240 -0
- package/dist/metadata.js +34 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -271,6 +271,27 @@ resourceGraph TodoResources @id("resource_graph_todo") {
|
|
|
271
271
|
|
|
272
272
|
The parser projects these rows into `metadata.semanticResourceGraphs`. Resource graphs are evidence, not proof: generated claims for borrow-checker soundness, alias safety, lifetime soundness, semantic equivalence, and auto-merge stay false. Compiler conversion routes can use these authored graphs as source-side resource, ownership, lifetime, and borrow-checker evidence while still requiring target proof before admission.
|
|
273
273
|
|
|
274
|
+
## Authored interlingua syntax
|
|
275
|
+
|
|
276
|
+
`.frontier` files can carry universal interlingua route evidence directly in `interlingua` or `universalInterlingua` blocks. These blocks describe the source lift, represented and missing semantic layers, constraint edges, proof obligations, and target lowering disposition for a route without claiming semantic equivalence.
|
|
277
|
+
|
|
278
|
+
```frontier
|
|
279
|
+
interlingua JsToRust @id("interlingua_js_rust") {
|
|
280
|
+
route conversion_route_javascript_to_rust
|
|
281
|
+
sourceLanguage javascript
|
|
282
|
+
target rust
|
|
283
|
+
mode target-adapter
|
|
284
|
+
lift source @id("lift_js") sourceImport native_import_js sourcePath src/public-api.js sourceHash sha256:source sourceMap source_map_js ownership symbol:displayName conflict symbol:displayName evidence evidence_translation proof proof_translation
|
|
285
|
+
layer symbols @id("layer_symbols") kind semantic-symbol status represented evidence evidence_translation
|
|
286
|
+
layer ownership @id("layer_ownership") kind semantic-ownership status missing missingEvidence translation-borrow-scope:borrow-across-await
|
|
287
|
+
constraint borrowAwait @id("constraint_borrow_await") family borrow-scope layer semantic-ownership status needs-evidence action collect-borrow-scope required shared-borrow-compatible|borrow-across-await represented shared-borrow-compatible missing borrow-across-await missingEvidence translation-borrow-scope:borrow-across-await evidence evidence_borrow_scope obligation obligation_borrow_await
|
|
288
|
+
obligation borrowAwait @id("obligation_borrow_await") edge constraint_borrow_await family borrow-scope kind borrow-across-await status missing missingEvidence translation-borrow-scope:borrow-across-await evidence evidence_borrow_scope
|
|
289
|
+
lowering rustAdapter @id("lowering_rust_adapter") disposition target-adapter adapter fixture-js-rust adapterKind targetProjection readiness needs-review lossClass targetAdapterProjection proofEvidence proof_translation missingEvidence host-target-adapter-review review adapter-review
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
The parser projects these rows into `metadata.universalInterlingua`. Interlingua records are route evidence: they expose queryable layer kinds, constraint families, obligation kinds/statuses, lowering disposition, proof ids, and missing evidence while keeping `autoMergeClaim` and `semanticEquivalenceClaim` false. The compiler can merge matching authored records into generated conversion routes by route id or source/target.
|
|
294
|
+
|
|
274
295
|
## Authored conversion syntax
|
|
275
296
|
|
|
276
297
|
`.frontier` files can carry universal conversion evidence directly in `conversion` or `universalConversionPlan` blocks. The parser projects these records into `metadata.universalConversionPlan` for the compiler facade and downstream semantic merge tooling.
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { actionNode, capabilityNode, createDocument, effectNode, entityNode, ext
|
|
|
2
2
|
import { parseConstraintSpaceBlock } from './constraint-space.js';
|
|
3
3
|
import { parseConversionBlock } from './conversion.js';
|
|
4
4
|
import { parseDecisionGraphBlock } from './decision-graph.js';
|
|
5
|
+
import { parseInterlinguaBlock } from './interlingua.js';
|
|
5
6
|
import { createParsedMetadata } from './metadata.js';
|
|
6
7
|
import { parseSemanticOperationsBlock } from './operations.js';
|
|
7
8
|
import { parseParadigmBlock } from './paradigm.js';
|
|
@@ -18,6 +19,7 @@ export function parseFrontierSource(source, options = {}) {
|
|
|
18
19
|
const conversionBlocks = [];
|
|
19
20
|
const constraintSpaceBlocks = [];
|
|
20
21
|
const decisionGraphBlocks = [];
|
|
22
|
+
const interlinguaBlocks = [];
|
|
21
23
|
const resourceGraphBlocks = [];
|
|
22
24
|
const nativeSourceBlocks = [];
|
|
23
25
|
const documentId = options.id ?? readId(source) ?? 'mod_frontier';
|
|
@@ -45,9 +47,10 @@ export function parseFrontierSource(source, options = {}) {
|
|
|
45
47
|
if (block.kind === 'conversion' || block.kind === 'universalConversionPlan') conversionBlocks.push(parseConversionBlock(block));
|
|
46
48
|
if (block.kind === 'constraintSpace' || block.kind === 'possibilitySpace') constraintSpaceBlocks.push(parseConstraintSpaceBlock(block));
|
|
47
49
|
if (block.kind === 'decisionGraph' || block.kind === 'admissionGraph') decisionGraphBlocks.push(parseDecisionGraphBlock(block));
|
|
50
|
+
if (block.kind === 'interlingua' || block.kind === 'universalInterlingua') interlinguaBlocks.push(parseInterlinguaBlock(block));
|
|
48
51
|
if (block.kind === 'resourceGraph' || block.kind === 'semanticResourceGraph') resourceGraphBlocks.push(parseResourceGraphBlock(block));
|
|
49
52
|
}
|
|
50
|
-
const metadata = createParsedMetadata({ proofBlocks, paradigmBlocks, operationBlocks, conversionBlocks, constraintSpaceBlocks, decisionGraphBlocks, resourceGraphBlocks, nativeSourceBlocks });
|
|
53
|
+
const metadata = createParsedMetadata({ proofBlocks, paradigmBlocks, operationBlocks, conversionBlocks, constraintSpaceBlocks, decisionGraphBlocks, interlinguaBlocks, resourceGraphBlocks, nativeSourceBlocks });
|
|
51
54
|
return createDocument({ id: documentId, name: documentName, nodes, ...(metadata ? { metadata } : {}) });
|
|
52
55
|
}
|
|
53
56
|
|
|
@@ -57,7 +60,7 @@ function readName(source) { return /module\s+([A-Za-z_$][\w$]*)/.exec(source)?.[
|
|
|
57
60
|
function readId(source) { return /module\s+[A-Za-z_$][\w$]*\s+@id\(\s*["']([^"']+)["']\s*\)/.exec(source)?.[1]; }
|
|
58
61
|
function readBlocks(source) {
|
|
59
62
|
const blocks = [];
|
|
60
|
-
const header = /\b(entity|state|action|view|migration|capability|effect|type|extern|lattice|nativeSource|target|proof|paradigm|paradigmSemantics|operations|semanticOperations|conversion|universalConversionPlan|constraintSpace|possibilitySpace|decisionGraph|admissionGraph|resourceGraph|semanticResourceGraph)\s+([^{}]+)\{/g;
|
|
63
|
+
const header = /\b(entity|state|action|view|migration|capability|effect|type|extern|lattice|nativeSource|target|proof|paradigm|paradigmSemantics|operations|semanticOperations|conversion|universalConversionPlan|constraintSpace|possibilitySpace|decisionGraph|admissionGraph|interlingua|universalInterlingua|resourceGraph|semanticResourceGraph)\s+([^{}]+)\{/g;
|
|
61
64
|
let match;
|
|
62
65
|
while ((match = header.exec(source))) {
|
|
63
66
|
let depth = 1; let index = header.lastIndex;
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
const GROUPS = {
|
|
2
|
+
layer: 'layerRecords',
|
|
3
|
+
constraint: 'constraintEdges',
|
|
4
|
+
edge: 'constraintEdges',
|
|
5
|
+
obligation: 'obligations',
|
|
6
|
+
proofObligation: 'obligations',
|
|
7
|
+
lowering: 'loweringRecords',
|
|
8
|
+
lift: 'liftRecords',
|
|
9
|
+
evidence: 'evidenceRecords'
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function parseInterlinguaBlock(block) {
|
|
13
|
+
const name = nameFrom(block.header);
|
|
14
|
+
const record = {
|
|
15
|
+
kind: 'frontier.lang.universalInterlinguaRecord',
|
|
16
|
+
version: 1,
|
|
17
|
+
id: idFrom(block.header, `interlingua_${name}`),
|
|
18
|
+
routeId: readLine('route', block.body) ?? readLine('routeId', block.body),
|
|
19
|
+
sourceLanguage: readLine('sourceLanguage', block.body) ?? readLine('source', block.body),
|
|
20
|
+
target: readLine('target', block.body),
|
|
21
|
+
mode: readLine('mode', block.body),
|
|
22
|
+
layerRecords: [],
|
|
23
|
+
constraintEdges: [],
|
|
24
|
+
obligations: [],
|
|
25
|
+
loweringRecords: [],
|
|
26
|
+
liftRecords: [],
|
|
27
|
+
evidenceRecords: [],
|
|
28
|
+
claims: {
|
|
29
|
+
autoMergeClaim: false,
|
|
30
|
+
semanticEquivalenceClaim: false
|
|
31
|
+
},
|
|
32
|
+
metadata: { name, authoredFrontierInterlingua: true }
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
for (const rawLine of block.body.split('\n')) {
|
|
36
|
+
const line = rawLine.trim();
|
|
37
|
+
if (!line || line.startsWith('#') || isPropertyLine(line)) continue;
|
|
38
|
+
const match = /^([A-Za-z_$][\w$-]*)\s+([A-Za-z_$][\w$-]*)(.*)$/.exec(line);
|
|
39
|
+
if (!match) continue;
|
|
40
|
+
const [, rowKind, rowName, rest] = match;
|
|
41
|
+
const normalized = normalizeRowKind(rowKind);
|
|
42
|
+
const parsed = parseInterlinguaRow(normalized, rowName, rest, record);
|
|
43
|
+
const group = GROUPS[normalized];
|
|
44
|
+
if (parsed && group) record[group].push(parsed);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
record.lift = summarizeLift(record);
|
|
48
|
+
record.layers = summarizeLayers(record.layerRecords, record.constraintEdges);
|
|
49
|
+
record.constraints = summarizeConstraints(record.constraintEdges, record.obligations);
|
|
50
|
+
record.lowering = summarizeLowering(record);
|
|
51
|
+
record.query = summarizeQuery(record);
|
|
52
|
+
record.summary = summarize(record);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
id: record.id,
|
|
56
|
+
record,
|
|
57
|
+
records: [record, ...record.constraintEdges, ...record.obligations, ...record.layerRecords, ...record.loweringRecords, ...record.liftRecords, ...record.evidenceRecords],
|
|
58
|
+
summary: {
|
|
59
|
+
recordCount: 1,
|
|
60
|
+
...record.summary
|
|
61
|
+
},
|
|
62
|
+
metadata: { name }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function parseInterlinguaRow(kind, name, text, parent) {
|
|
67
|
+
const common = commonRecord(kind, name, text, parent);
|
|
68
|
+
if (kind === 'layer') return cleanRecord({ ...common, layerKind: readInlineWord('layerKind', text) ?? readInlineWord('kind', text) ?? name, status: readInlineWord('status', text) ?? 'represented', sourceIds: readInlineList(text, 'source', 'sourceId', 'sourceIds'), targetIds: readInlineList(text, 'target', 'targetId', 'targetIds'), missingEvidence: readInlineList(text, 'missingEvidence'), blockers: readInlineList(text, 'blocker', 'blockers'), review: readInlineList(text, 'review') });
|
|
69
|
+
if (kind === 'constraint') return cleanRecord({ ...common, family: readInlineWord('family', text) ?? readInlineWord('kind', text) ?? name, layerKind: readInlineWord('layer', text) ?? readInlineWord('layerKind', text), status: readInlineWord('status', text) ?? 'required', action: readInlineWord('action', text), sourceId: readInlineWord('source', text) ?? readInlineWord('sourceId', text), requiredKinds: readInlineList(text, 'required', 'requiredKind', 'requiredKinds'), representedKinds: readInlineList(text, 'represented', 'representedKind', 'representedKinds'), missingKinds: readInlineList(text, 'missing', 'missingKind', 'missingKinds'), missingEvidence: readInlineList(text, 'missingEvidence'), blockers: readInlineList(text, 'blocker', 'blockers'), review: readInlineList(text, 'review'), obligationIds: readInlineList(text, 'obligation', 'obligationId', 'obligationIds') });
|
|
70
|
+
if (kind === 'obligation') return cleanRecord({ ...common, edgeId: readInlineWord('edge', text) ?? readInlineWord('edgeId', text), family: readInlineWord('family', text), obligationKind: readInlineWord('obligationKind', text) ?? readInlineWord('kind', text) ?? name, status: readInlineWord('status', text) ?? 'required', sourceId: readInlineWord('source', text) ?? readInlineWord('sourceId', text), sourceNodeIds: readInlineList(text, 'sourceNode', 'sourceNodeIds'), targetNodeIds: readInlineList(text, 'targetNode', 'targetNodeIds'), missingEvidence: readInlineList(text, 'missingEvidence'), severity: readInlineWord('severity', text) });
|
|
71
|
+
if (kind === 'lowering') return cleanRecord({ ...common, disposition: readInlineWord('disposition', text) ?? readInlineWord('kind', text), adapterId: readInlineWord('adapter', text) ?? readInlineWord('adapterId', text), adapterKind: readInlineWord('adapterKind', text), readiness: readInlineWord('readiness', text), routeAction: readInlineWord('routeAction', text), lossClass: readInlineWord('lossClass', text), lossIds: readInlineList(text, 'loss', 'lossId', 'lossIds'), proofEvidenceIds: readInlineList(text, 'proofEvidence', 'proofEvidenceIds'), missingEvidence: readInlineList(text, 'missingEvidence'), blockers: readInlineList(text, 'blocker', 'blockers'), review: readInlineList(text, 'review') });
|
|
72
|
+
if (kind === 'lift') return cleanRecord({ ...common, sourceImportIds: readInlineList(text, 'sourceImport', 'sourceImportId', 'sourceImportIds'), sourcePaths: readInlineList(text, 'sourcePath', 'sourcePaths', 'path', 'paths'), sourceHashes: readInlineList(text, 'sourceHash', 'sourceHashes'), sourceMapIds: readInlineList(text, 'sourceMap', 'sourceMapId', 'sourceMapIds'), sourceMapMappingIds: readInlineList(text, 'sourceMapMapping', 'sourceMapMappingId', 'sourceMapMappingIds'), ownershipKeys: readInlineList(text, 'ownership', 'ownershipKey', 'ownershipKeys'), conflictKeys: readInlineList(text, 'conflict', 'conflictKey', 'conflictKeys'), proofIds: readInlineList(text, 'proof', 'proofId', 'proofIds') });
|
|
73
|
+
if (kind === 'evidence') return cleanRecord({ ...common, evidenceKind: readInlineWord('evidenceKind', text) ?? readInlineWord('kind', text), status: readInlineWord('status', text), path: readInlineWord('path', text), command: readInlineQuoted('command', text) ?? readInlineWord('command', text) });
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function commonRecord(kind, name, text, parent) {
|
|
78
|
+
return cleanRecord({
|
|
79
|
+
id: idFrom(text, `${recordPrefix(kind)}_${name}`),
|
|
80
|
+
recordKind: `frontier.lang.universalInterlingua.${recordKind(kind)}`,
|
|
81
|
+
name,
|
|
82
|
+
routeId: readInlineWord('route', text) ?? readInlineWord('routeId', text) ?? parent.routeId,
|
|
83
|
+
sourceLanguage: readInlineWord('sourceLanguage', text) ?? parent.sourceLanguage,
|
|
84
|
+
target: readInlineWord('target', text) ?? parent.target,
|
|
85
|
+
evidenceIds: readInlineList(text, 'evidence', 'evidenceId', 'evidenceIds'),
|
|
86
|
+
metadata: { authoredName: name }
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function summarizeLift(record) {
|
|
91
|
+
return cleanRecord({
|
|
92
|
+
sourceLanguage: record.sourceLanguage,
|
|
93
|
+
sourceImportIds: unique(record.liftRecords.flatMap((entry) => entry.sourceImportIds ?? [])),
|
|
94
|
+
sourcePaths: unique(record.liftRecords.flatMap((entry) => entry.sourcePaths ?? [])),
|
|
95
|
+
sourceHashes: unique(record.liftRecords.flatMap((entry) => entry.sourceHashes ?? [])),
|
|
96
|
+
sourceMapIds: unique(record.liftRecords.flatMap((entry) => entry.sourceMapIds ?? [])),
|
|
97
|
+
sourceMapMappingIds: unique(record.liftRecords.flatMap((entry) => entry.sourceMapMappingIds ?? [])),
|
|
98
|
+
ownershipKeys: unique(record.liftRecords.flatMap((entry) => entry.ownershipKeys ?? [])),
|
|
99
|
+
conflictKeys: unique(record.liftRecords.flatMap((entry) => entry.conflictKeys ?? [])),
|
|
100
|
+
evidenceIds: unique(allEvidence(record)),
|
|
101
|
+
proofIds: unique(record.liftRecords.flatMap((entry) => entry.proofIds ?? []))
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function summarizeLayers(layers, edges) {
|
|
106
|
+
const byStatus = (status) => unique(layers.filter((layer) => layer.status === status).map((layer) => layer.layerKind));
|
|
107
|
+
return {
|
|
108
|
+
kinds: unique([...layers.map((layer) => layer.layerKind), ...edges.map((edge) => edge.layerKind)]),
|
|
109
|
+
representedKinds: byStatus('represented'),
|
|
110
|
+
missingKinds: unique([...byStatus('missing'), ...edges.filter((edge) => (edge.missingKinds ?? []).length || (edge.missingEvidence ?? []).length).map((edge) => edge.layerKind)]),
|
|
111
|
+
reviewKinds: byStatus('review'),
|
|
112
|
+
blockedKinds: byStatus('blocked'),
|
|
113
|
+
constructCount: layers.length,
|
|
114
|
+
representedCount: byStatus('represented').length,
|
|
115
|
+
missingCount: byStatus('missing').length,
|
|
116
|
+
reviewCount: byStatus('review').length,
|
|
117
|
+
blockedCount: byStatus('blocked').length
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function summarizeConstraints(edges, obligations) {
|
|
122
|
+
const normalizedObligations = obligations.map((obligation) => cleanRecord({ ...obligation, kind: obligation.obligationKind ?? obligation.kind }));
|
|
123
|
+
return {
|
|
124
|
+
edges,
|
|
125
|
+
edgeCount: edges.length,
|
|
126
|
+
obligations: normalizedObligations,
|
|
127
|
+
obligationCount: normalizedObligations.length,
|
|
128
|
+
families: unique(edges.map((edge) => edge.family)),
|
|
129
|
+
statuses: unique(edges.map((edge) => edge.status)),
|
|
130
|
+
actions: unique(edges.map((edge) => edge.action)),
|
|
131
|
+
sourceIds: unique(edges.map((edge) => edge.sourceId)),
|
|
132
|
+
evidenceIds: unique(edges.flatMap((edge) => edge.evidenceIds ?? [])),
|
|
133
|
+
requiredKinds: unique(edges.flatMap((edge) => edge.requiredKinds ?? [])),
|
|
134
|
+
representedKinds: unique(edges.flatMap((edge) => edge.representedKinds ?? [])),
|
|
135
|
+
missingKinds: unique(edges.flatMap((edge) => edge.missingKinds ?? [])),
|
|
136
|
+
missingEvidence: unique(edges.flatMap((edge) => edge.missingEvidence ?? [])),
|
|
137
|
+
obligationKinds: unique(normalizedObligations.map((obligation) => obligation.kind)),
|
|
138
|
+
obligationStatuses: unique(normalizedObligations.map((obligation) => obligation.status)),
|
|
139
|
+
obligationEvidenceIds: unique(normalizedObligations.flatMap((obligation) => obligation.evidenceIds ?? [])),
|
|
140
|
+
obligationMissingEvidence: unique(normalizedObligations.flatMap((obligation) => obligation.missingEvidence ?? [])),
|
|
141
|
+
blockers: unique(edges.flatMap((edge) => edge.blockers ?? [])),
|
|
142
|
+
review: unique(edges.flatMap((edge) => edge.review ?? []))
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function summarizeLowering(record) {
|
|
147
|
+
const latest = record.loweringRecords.at(-1) ?? {};
|
|
148
|
+
return cleanRecord({
|
|
149
|
+
disposition: latest.disposition,
|
|
150
|
+
mode: record.mode,
|
|
151
|
+
routeAction: latest.routeAction,
|
|
152
|
+
lossClass: latest.lossClass,
|
|
153
|
+
adapterId: latest.adapterId,
|
|
154
|
+
adapterKind: latest.adapterKind,
|
|
155
|
+
readiness: latest.readiness,
|
|
156
|
+
proofEvidenceIds: unique(record.loweringRecords.flatMap((entry) => entry.proofEvidenceIds ?? [])),
|
|
157
|
+
evidenceIds: unique(allEvidence(record)),
|
|
158
|
+
missingEvidence: unique(record.loweringRecords.flatMap((entry) => entry.missingEvidence ?? [])),
|
|
159
|
+
lossIds: unique(record.loweringRecords.flatMap((entry) => entry.lossIds ?? [])),
|
|
160
|
+
blockers: unique(record.loweringRecords.flatMap((entry) => entry.blockers ?? [])),
|
|
161
|
+
review: unique(record.loweringRecords.flatMap((entry) => entry.review ?? []))
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function summarizeQuery(record) {
|
|
166
|
+
return {
|
|
167
|
+
layerKinds: record.layers.kinds,
|
|
168
|
+
representedLayerKinds: record.layers.representedKinds,
|
|
169
|
+
missingLayerKinds: record.layers.missingKinds,
|
|
170
|
+
reviewLayerKinds: record.layers.reviewKinds,
|
|
171
|
+
blockedLayerKinds: record.layers.blockedKinds,
|
|
172
|
+
constraintFamilies: record.constraints.families,
|
|
173
|
+
constraintStatuses: record.constraints.statuses,
|
|
174
|
+
constraintActions: record.constraints.actions,
|
|
175
|
+
constraintSourceIds: record.constraints.sourceIds,
|
|
176
|
+
constraintEvidenceIds: record.constraints.evidenceIds,
|
|
177
|
+
constraintRequiredKinds: record.constraints.requiredKinds,
|
|
178
|
+
constraintRepresentedKinds: record.constraints.representedKinds,
|
|
179
|
+
constraintMissingKinds: record.constraints.missingKinds,
|
|
180
|
+
constraintMissingEvidence: record.constraints.missingEvidence,
|
|
181
|
+
constraintObligationKinds: record.constraints.obligationKinds,
|
|
182
|
+
constraintObligationStatuses: record.constraints.obligationStatuses,
|
|
183
|
+
constraintObligationEvidenceIds: record.constraints.obligationEvidenceIds,
|
|
184
|
+
constraintObligationMissingEvidence: record.constraints.obligationMissingEvidence,
|
|
185
|
+
loweringDisposition: record.lowering.disposition,
|
|
186
|
+
missingEvidence: unique([...(record.lowering.missingEvidence ?? []), ...(record.constraints.missingEvidence ?? [])]),
|
|
187
|
+
proofEvidenceIds: record.lowering.proofEvidenceIds ?? [],
|
|
188
|
+
targetAdapterId: record.lowering.adapterId
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function summarize(record) {
|
|
193
|
+
return {
|
|
194
|
+
layerCount: record.layers.constructCount,
|
|
195
|
+
constraintCount: record.constraints.edgeCount,
|
|
196
|
+
obligationCount: record.constraints.obligationCount,
|
|
197
|
+
loweringCount: record.loweringRecords.length,
|
|
198
|
+
liftCount: record.liftRecords.length,
|
|
199
|
+
evidenceCount: record.evidenceRecords.length,
|
|
200
|
+
missingEvidenceCount: record.query.missingEvidence.length,
|
|
201
|
+
blockerCount: (record.lowering.blockers ?? []).length + (record.constraints.blockers ?? []).length
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function allEvidence(record) {
|
|
206
|
+
return [...record.evidenceRecords.map((entry) => entry.id), ...record.layerRecords.flatMap((entry) => entry.evidenceIds ?? []), ...record.constraintEdges.flatMap((entry) => entry.evidenceIds ?? []), ...record.obligations.flatMap((entry) => entry.evidenceIds ?? []), ...record.liftRecords.flatMap((entry) => entry.evidenceIds ?? [])];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function normalizeRowKind(kind) {
|
|
210
|
+
if (kind === 'constraintEdge') return 'constraint';
|
|
211
|
+
if (kind === 'proof' || kind === 'proofObligation') return 'obligation';
|
|
212
|
+
if (kind === 'lower' || kind === 'lowering') return 'lowering';
|
|
213
|
+
if (kind === 'source' || kind === 'sourceLift') return 'lift';
|
|
214
|
+
return kind;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function recordKind(kind) {
|
|
218
|
+
if (kind === 'constraint') return 'constraintEdge';
|
|
219
|
+
if (kind === 'obligation') return 'constraintObligation';
|
|
220
|
+
return kind;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function recordPrefix(kind) { return recordKind(kind).replace(/[A-Z]/g, (value) => `_${value.toLowerCase()}`); }
|
|
224
|
+
function isPropertyLine(line) { return /^(route|routeId|sourceLanguage|source|target|mode)\s+/.test(line); }
|
|
225
|
+
function idFrom(text, fallback) { return /@id\(\s*["']([^"']+)["']\s*\)/.exec(text)?.[1] ?? fallback; }
|
|
226
|
+
function nameFrom(header) { return /^([A-Za-z_$][\w$]*)/.exec(header)?.[1] ?? 'Interlingua'; }
|
|
227
|
+
function readLine(label, body) { return new RegExp('^\\s*' + label + '\\s+([^\\n]+)', 'm').exec(body)?.[1]?.trim(); }
|
|
228
|
+
function readInlineWord(label, text) { return new RegExp('(?:^|\\s)' + label + '\\s+([^\\s,]+)').exec(text)?.[1]?.trim(); }
|
|
229
|
+
function readInlineQuoted(label, text) { return new RegExp("(?:^|\\s)" + label + "\\s+[\"']([^\"']+)[\"']").exec(text)?.[1]?.trim(); }
|
|
230
|
+
function readInlineList(text, ...labels) {
|
|
231
|
+
for (const label of labels) {
|
|
232
|
+
const value = new RegExp('(?:^|\\s)' + label + '\\s+([^\\s]+)').exec(text)?.[1]?.trim();
|
|
233
|
+
if (value) return value.split(/[|,]/).map((item) => item.trim()).filter(Boolean);
|
|
234
|
+
}
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
237
|
+
function unique(values = []) { return [...new Set(values.filter(Boolean))]; }
|
|
238
|
+
function cleanRecord(record) {
|
|
239
|
+
return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined && (!Array.isArray(value) || value.length > 0)));
|
|
240
|
+
}
|
package/dist/metadata.js
CHANGED
|
@@ -21,7 +21,7 @@ const PARADIGM_GROUPS = [
|
|
|
21
21
|
'loweringRecords'
|
|
22
22
|
];
|
|
23
23
|
|
|
24
|
-
export function createParsedMetadata({ proofBlocks = [], paradigmBlocks = [], operationBlocks = [], conversionBlocks = [], constraintSpaceBlocks = [], decisionGraphBlocks = [], resourceGraphBlocks = [], nativeSourceBlocks = [] } = {}) {
|
|
24
|
+
export function createParsedMetadata({ proofBlocks = [], paradigmBlocks = [], operationBlocks = [], conversionBlocks = [], constraintSpaceBlocks = [], decisionGraphBlocks = [], interlinguaBlocks = [], resourceGraphBlocks = [], nativeSourceBlocks = [] } = {}) {
|
|
25
25
|
const metadata = {};
|
|
26
26
|
if (proofBlocks.length) metadata.proof = mergeProofBlocks(proofBlocks);
|
|
27
27
|
if (paradigmBlocks.length) metadata.paradigmSemantics = mergeParadigmBlocks(paradigmBlocks);
|
|
@@ -29,6 +29,7 @@ export function createParsedMetadata({ proofBlocks = [], paradigmBlocks = [], op
|
|
|
29
29
|
if (conversionBlocks.length) metadata.universalConversionPlan = mergeConversionBlocks(conversionBlocks);
|
|
30
30
|
if (constraintSpaceBlocks.length) metadata.constraintSpaces = mergeConstraintSpaceBlocks(constraintSpaceBlocks);
|
|
31
31
|
if (decisionGraphBlocks.length) metadata.decisionGraph = mergeDecisionGraphBlocks(decisionGraphBlocks);
|
|
32
|
+
if (interlinguaBlocks.length) metadata.universalInterlingua = mergeInterlinguaBlocks(interlinguaBlocks);
|
|
32
33
|
if (resourceGraphBlocks.length) metadata.semanticResourceGraphs = mergeResourceGraphBlocks(resourceGraphBlocks);
|
|
33
34
|
if (nativeSourceBlocks.some((block) => block.sourceMaps.length || block.mergeCandidates.length || block.evidence.length)) {
|
|
34
35
|
metadata.universalAst = mergeNativeSourceBlocks(nativeSourceBlocks);
|
|
@@ -153,6 +154,38 @@ function mergeDecisionGraphBlocks(blocks) {
|
|
|
153
154
|
};
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
function mergeInterlinguaBlocks(blocks) {
|
|
158
|
+
const interlinguaRecords = blocks.map((block) => block.record).filter(Boolean);
|
|
159
|
+
const records = blocks.flatMap((block) => block.records ?? []);
|
|
160
|
+
return {
|
|
161
|
+
id: blocks.length === 1 ? blocks[0].id : 'universalInterlingua:source',
|
|
162
|
+
interlinguaRecords,
|
|
163
|
+
records,
|
|
164
|
+
recordIds: ids(records),
|
|
165
|
+
interlinguaRecordIds: ids(interlinguaRecords),
|
|
166
|
+
layerIds: blocks.flatMap((block) => ids(block.record?.layerRecords)),
|
|
167
|
+
constraintIds: blocks.flatMap((block) => ids(block.record?.constraintEdges)),
|
|
168
|
+
obligationIds: blocks.flatMap((block) => ids(block.record?.obligations)),
|
|
169
|
+
loweringIds: blocks.flatMap((block) => ids(block.record?.loweringRecords)),
|
|
170
|
+
liftIds: blocks.flatMap((block) => ids(block.record?.liftRecords)),
|
|
171
|
+
evidenceIds: [...new Set(blocks.flatMap((block) => block.record?.query?.proofEvidenceIds ?? []).concat(blocks.flatMap((block) => block.record?.query?.constraintEvidenceIds ?? [])))],
|
|
172
|
+
routeIds: [...new Set(interlinguaRecords.map((record) => record.routeId).filter(Boolean))],
|
|
173
|
+
summary: {
|
|
174
|
+
interlinguaCount: interlinguaRecords.length,
|
|
175
|
+
recordCount: records.length,
|
|
176
|
+
layerCount: sum(blocks, 'layerCount'),
|
|
177
|
+
constraintCount: sum(blocks, 'constraintCount'),
|
|
178
|
+
obligationCount: sum(blocks, 'obligationCount'),
|
|
179
|
+
loweringCount: sum(blocks, 'loweringCount'),
|
|
180
|
+
liftCount: sum(blocks, 'liftCount'),
|
|
181
|
+
evidenceCount: sum(blocks, 'evidenceCount'),
|
|
182
|
+
missingEvidenceCount: sum(blocks, 'missingEvidenceCount'),
|
|
183
|
+
blockerCount: sum(blocks, 'blockerCount')
|
|
184
|
+
},
|
|
185
|
+
metadata: { authoredInterlinguaBlockIds: blocks.map((block) => block.id) }
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
156
189
|
function mergeResourceGraphBlocks(blocks) {
|
|
157
190
|
const graphs = blocks.map((block) => block.graph).filter(Boolean);
|
|
158
191
|
const records = blocks.flatMap((block) => block.records ?? []);
|
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.21",
|
|
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/resource-graph-smoke.mjs",
|
|
25
|
+
"test": "npm run build && node test/smoke.mjs && node test/resource-graph-smoke.mjs && node test/interlingua-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",
|