@shapeshift-labs/frontier-lang-parser 0.3.71 → 0.3.73

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/metadata.js CHANGED
@@ -264,6 +264,13 @@ function mergeResourceGraphBlocks(blocks) {
264
264
  lifetimeRelationIds: blocks.flatMap((block) => ids(block.graph?.lifetimeRelations)),
265
265
  borrowScopeIds: blocks.flatMap((block) => ids(block.graph?.borrowScopes)),
266
266
  unsafeBoundaryIds: blocks.flatMap((block) => ids(block.graph?.unsafeBoundaries)),
267
+ memoryRegionIds: blocks.flatMap((block) => ids(block.graph?.memoryRegions)),
268
+ dataLayoutIds: blocks.flatMap((block) => ids(block.graph?.dataLayouts)),
269
+ pointerEdgeIds: blocks.flatMap((block) => ids(block.graph?.pointerEdges)),
270
+ memoryAccessIds: blocks.flatMap((block) => ids(block.graph?.memoryAccesses)),
271
+ abiBoundaryIds: blocks.flatMap((block) => ids(block.graph?.abiBoundaries)),
272
+ trapIds: blocks.flatMap((block) => ids(block.graph?.traps)),
273
+ undefinedBehaviorIds: blocks.flatMap((block) => ids(block.graph?.undefinedBehaviors)),
267
274
  conflictIds: blocks.flatMap((block) => ids(block.graph?.conflicts)),
268
275
  proofObligationIds: blocks.flatMap((block) => ids(block.graph?.proofObligations)),
269
276
  summary: {
@@ -280,9 +287,20 @@ function mergeResourceGraphBlocks(blocks) {
280
287
  lifetimeRelationCount: sum(blocks, 'lifetimeRelations'),
281
288
  borrowScopeCount: sum(blocks, 'borrowScopes'),
282
289
  unsafeBoundaryCount: sum(blocks, 'unsafeBoundaries'),
290
+ memoryRegionCount: sum(blocks, 'memoryRegions'),
291
+ dataLayoutCount: sum(blocks, 'dataLayouts'),
292
+ pointerEdgeCount: sum(blocks, 'pointerEdges'),
293
+ memoryAccessCount: sum(blocks, 'memoryAccesses'),
294
+ abiBoundaryCount: sum(blocks, 'abiBoundaries'),
295
+ trapCount: sum(blocks, 'traps'),
296
+ undefinedBehaviorCount: sum(blocks, 'undefinedBehaviors'),
297
+ lowLevelPrimitiveCount: sum(blocks, 'lowLevelPrimitives'),
283
298
  conflictCount: sum(blocks, 'conflicts'),
284
299
  proofObligationCount: sum(blocks, 'proofObligations'),
285
- unsafeBoundariesWithoutProof: sum(blocks, 'unsafeBoundariesWithoutProof')
300
+ unsafeBoundariesWithoutProof: sum(blocks, 'unsafeBoundariesWithoutProof'),
301
+ failClosedTrapCount: sum(blocks, 'failClosedTraps'),
302
+ trapWithoutProofCount: sum(blocks, 'trapsWithoutProof'),
303
+ undefinedBehaviorWithoutProofCount: sum(blocks, 'undefinedBehaviorsWithoutProof')
286
304
  },
287
305
  metadata: { authoredResourceGraphBlockIds: blocks.map((block) => block.id) }
288
306
  };
@@ -0,0 +1,25 @@
1
+ export function parseLowLevelResourceRecord(kind, common, name, text) {
2
+ if (kind === 'memoryRegion') return cleanRecord({ ...common, resourceId: word('resource', text) ?? word('resourceId', text), memoryKind: word('memoryKind', text) ?? word('kind', text) ?? name, regionKind: word('regionKind', text), addressSpace: word('addressSpace', text) ?? word('space', text), address: word('address', text) ?? word('baseAddress', text), sizeBytes: number('sizeBytes', text) ?? number('size', text), alignmentBytes: number('alignmentBytes', text) ?? number('alignment', text), pointerWidth: number('pointerWidth', text), endian: word('endian', text) ?? word('endianness', text), volatile: flag('volatile', text), atomic: flag('atomic', text), shared: flag('shared', text) });
3
+ if (kind === 'dataLayout') return cleanRecord({ ...common, resourceId: word('resource', text) ?? word('resourceId', text), typeId: word('type', text) ?? word('typeId', text), structId: word('struct', text) ?? word('structId', text), fieldId: word('field', text) ?? word('fieldId', text), bitfieldId: word('bitfield', text) ?? word('bitfieldId', text), layoutKind: word('layoutKind', text) ?? word('kind', text), repr: word('repr', text), abi: word('abi', text), endian: word('endian', text) ?? word('endianness', text), sizeBytes: number('sizeBytes', text) ?? number('size', text), alignmentBytes: number('alignmentBytes', text) ?? number('alignment', text), offsetBytes: number('offsetBytes', text) ?? number('offset', text), bitWidth: number('bitWidth', text) ?? number('width', text), fieldOrder: list(text, 'fieldOrder', 'fields'), constraintKinds: list(text, 'constraint', 'constraints', 'constraintKind', 'constraintKinds') });
4
+ if (kind === 'pointerEdge') return cleanRecord({ ...common, resourceId: word('resource', text) ?? word('resourceId', text), targetResourceId: word('targetResource', text) ?? word('targetResourceId', text) ?? word('target', text), ownerId: word('owner', text) ?? word('ownerId', text), lifetimeRegionId: word('lifetime', text) ?? word('lifetimeRegion', text) ?? word('lifetimeRegionId', text), pointerKind: word('pointerKind', text) ?? word('kind', text) ?? 'pointer', addressSpace: word('addressSpace', text) ?? word('space', text), pointerWidth: number('pointerWidth', text), aliasKind: word('aliasKind', text), mode: word('mode', text), provenance: word('provenance', text), nullable: flag('nullable', text), mutable: flag('mutable', text) });
5
+ if (kind === 'memoryAccess') return cleanRecord({ ...common, resourceId: word('resource', text) ?? word('resourceId', text), accessKind: word('accessKind', text) ?? word('kind', text) ?? name, operationKind: word('operation', text) ?? word('operationKind', text), memoryOrder: word('memoryOrder', text) ?? word('ordering', text), lockId: word('lock', text) ?? word('lockId', text), synchronizationKey: word('sync', text) ?? word('synchronizationKey', text), reads: list(text, 'read', 'reads'), writes: list(text, 'write', 'writes'), volatile: flag('volatile', text), atomic: flag('atomic', text), proofStatus: word('proofStatus', text) ?? word('status', text) ?? 'missing' });
6
+ if (kind === 'abiBoundary') return cleanRecord({ ...common, resourceId: word('resource', text) ?? word('resourceId', text), callableId: word('callable', text) ?? word('callableId', text), functionId: word('function', text) ?? word('functionId', text), boundaryKind: word('boundaryKind', text) ?? word('kind', text) ?? 'abi-boundary', abi: word('abi', text), abiKind: word('abiKind', text), callingConvention: word('callingConvention', text) ?? word('convention', text), pointerWidth: number('pointerWidth', text), endian: word('endian', text) ?? word('endianness', text), ffiBoundary: word('ffiBoundary', text), proofStatus: word('proofStatus', text) ?? word('status', text) ?? 'missing' });
7
+ if (kind === 'trap') return cleanRecord({ ...common, resourceId: word('resource', text) ?? word('resourceId', text), ownerId: word('owner', text) ?? word('ownerId', text), loanId: word('loan', text) ?? word('loanId', text), pointerEdgeId: word('pointer', text) ?? word('pointerEdge', text) ?? word('pointerEdgeId', text), memoryAccessId: word('memoryAccess', text) ?? word('memoryAccessId', text), unsafeBoundaryId: word('unsafeBoundary', text) ?? word('unsafeBoundaryId', text), operationKind: word('operation', text) ?? word('operationKind', text), instructionId: word('instruction', text) ?? word('instructionId', text), callableId: word('callable', text) ?? word('callableId', text), trapKind: word('trapKind', text) ?? word('kind', text) ?? name, trapCode: word('trapCode', text) ?? word('code', text), reasonCode: word('reasonCode', text) ?? word('code', text), condition: quoted('condition', text) ?? word('condition', text), status: word('status', text) ?? 'needs-proof', severity: word('severity', text) ?? 'error', proofStatus: word('proofStatus', text) ?? word('status', text) ?? 'missing', message: quoted('message', text), failClosed: common.failClosed ?? true, semanticEquivalenceClaim: false, runtimeEquivalenceClaim: false });
8
+ if (kind === 'undefinedBehavior') return cleanRecord({ ...common, resourceId: word('resource', text) ?? word('resourceId', text), ownerId: word('owner', text) ?? word('ownerId', text), loanId: word('loan', text) ?? word('loanId', text), pointerEdgeId: word('pointer', text) ?? word('pointerEdge', text) ?? word('pointerEdgeId', text), memoryAccessId: word('memoryAccess', text) ?? word('memoryAccessId', text), unsafeBoundaryId: word('unsafeBoundary', text) ?? word('unsafeBoundaryId', text), operationKind: word('operation', text) ?? word('operationKind', text), undefinedBehaviorKind: word('undefinedBehaviorKind', text) ?? word('behaviorKind', text) ?? word('kind', text) ?? name, language: word('language', text), reasonCode: word('reasonCode', text) ?? word('code', text), condition: quoted('condition', text) ?? word('condition', text), status: word('status', text) ?? 'needs-proof', severity: word('severity', text) ?? 'error', proofStatus: word('proofStatus', text) ?? word('status', text) ?? 'missing', message: quoted('message', text), failClosed: common.failClosed ?? true, semanticEquivalenceClaim: false, runtimeEquivalenceClaim: false });
9
+ return undefined;
10
+ }
11
+
12
+ function word(label, text) { return new RegExp('(?:^|\\s)' + label + '\\s+([^\\s,]+)').exec(text)?.[1]?.trim(); }
13
+ function quoted(label, text) { return new RegExp("(?:^|\\s)" + label + "\\s+[\"']([^\"']+)[\"']").exec(text)?.[1]?.trim(); }
14
+ function flag(label, text) { return new RegExp('(?:^|\\s)' + label + '(?:\\s|$)').test(text) || undefined; }
15
+ function number(label, text) { const value = word(label, text); return value === undefined ? undefined : Number(value); }
16
+ function list(text, ...labels) {
17
+ for (const label of labels) {
18
+ const value = new RegExp('(?:^|\\s)' + label + '\\s+([^\\s]+)').exec(text)?.[1]?.trim();
19
+ if (value) return value.split(/[|,]/).map((item) => item.trim()).filter(Boolean);
20
+ }
21
+ return undefined;
22
+ }
23
+ function cleanRecord(record) {
24
+ return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined && (!Array.isArray(value) || value.length > 0)));
25
+ }
@@ -1,4 +1,5 @@
1
1
  import { createRowIdentityTracker } from './row-identity.js';
2
+ import { parseLowLevelResourceRecord } from './resource-graph-low-level.js';
2
3
 
3
4
  const GROUPS = {
4
5
  resource: 'resources',
@@ -12,6 +13,13 @@ const GROUPS = {
12
13
  lifetimeRelation: 'lifetimeRelations',
13
14
  borrowScope: 'borrowScopes',
14
15
  unsafeBoundary: 'unsafeBoundaries',
16
+ memoryRegion: 'memoryRegions',
17
+ dataLayout: 'dataLayouts',
18
+ pointerEdge: 'pointerEdges',
19
+ memoryAccess: 'memoryAccesses',
20
+ abiBoundary: 'abiBoundaries',
21
+ trap: 'traps',
22
+ undefinedBehavior: 'undefinedBehaviors',
15
23
  conflict: 'conflicts',
16
24
  proofObligation: 'proofObligations'
17
25
  };
@@ -41,6 +49,13 @@ export function parseResourceGraphBlock(block) {
41
49
  borrowScopes: [],
42
50
  borrowScopeRegions: [],
43
51
  unsafeBoundaries: [],
52
+ memoryRegions: [],
53
+ dataLayouts: [],
54
+ pointerEdges: [],
55
+ memoryAccesses: [],
56
+ abiBoundaries: [],
57
+ traps: [],
58
+ undefinedBehaviors: [],
44
59
  conflicts: [],
45
60
  proofObligations: [],
46
61
  parser: { status: 'authored', errors: rowIdentity.errors },
@@ -54,14 +69,14 @@ export function parseResourceGraphBlock(block) {
54
69
  metadata: { name }
55
70
  };
56
71
 
57
- for (const rawLine of block.body.split('\n')) {
58
- const line = rawLine.trim();
72
+ for (const authoredLine of readAuthoredLines(block)) {
73
+ const line = authoredLine.text;
59
74
  if (!line || line.startsWith('#') || isGraphPropertyLine(line)) continue;
60
75
  const match = /^([A-Za-z_$][\w$-]*)\s+([A-Za-z_$][\w$-]*)(.*)$/.exec(line);
61
76
  if (!match) continue;
62
77
  const [, rowKind, rowName, rest] = match;
63
78
  const normalized = normalizeRowKind(rowKind);
64
- const record = parseResourceRecord(normalized, rowName, rest, graph);
79
+ const record = parseResourceRecord(normalized, rowName, rest, graph, authoredLine);
65
80
  const group = GROUPS[normalized];
66
81
  if (record && group) rowIdentity.push(graph[group], record, { rowKind, normalizedRowKind: normalized, name: rowName });
67
82
  }
@@ -73,9 +88,13 @@ export function parseResourceGraphBlock(block) {
73
88
  resourceIds: ids(graph.resources),
74
89
  ownerIds: ids(graph.owners),
75
90
  lifetimeRegionIds: ids(graph.lifetimeRegions),
91
+ trapIds: ids(graph.traps),
92
+ undefinedBehaviorIds: ids(graph.undefinedBehaviors),
93
+ failClosedTrapIds: ids(graph.traps.filter((record) => record.failClosed)),
94
+ lowLevelPrimitiveIds: ids([...graph.memoryRegions, ...graph.dataLayouts, ...graph.pointerEdges, ...graph.memoryAccesses, ...graph.abiBoundaries, ...graph.traps, ...graph.undefinedBehaviors]),
76
95
  sourcePaths: unique(allRecords(graph).map((record) => record.sourcePath)),
77
96
  evidenceIds: unique([...graph.evidenceIds, ...allRecords(graph).flatMap((record) => record.evidenceIds ?? [])]),
78
- blockerReasonCodes: unique(graph.conflicts.map((record) => record.reasonCode))
97
+ blockerReasonCodes: unique([...graph.conflicts, ...graph.traps, ...graph.undefinedBehaviors].map((record) => record.reasonCode))
79
98
  };
80
99
 
81
100
  return {
@@ -90,8 +109,8 @@ export function parseResourceGraphBlock(block) {
90
109
  };
91
110
  }
92
111
 
93
- function parseResourceRecord(kind, name, text, graph) {
94
- const common = commonRecord(kind, name, text, graph);
112
+ function parseResourceRecord(kind, name, text, graph, authoredLine = {}) {
113
+ const common = commonRecord(kind, name, text, graph, authoredLine);
95
114
  if (kind === 'resource') return cleanRecord({ ...common, resourceKind: readInlineWord('resourceKind', text) ?? readInlineWord('kind', text) ?? name, ownerId: readInlineWord('owner', text) ?? readInlineWord('ownerId', text), ownerName: readInlineWord('ownerName', text) });
96
115
  if (kind === 'owner') return cleanRecord({ ...common, ownerKind: readInlineWord('ownerKind', text) ?? readInlineWord('kind', text) ?? 'owner' });
97
116
  if (kind === 'loan') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), ownerId: readInlineWord('owner', text) ?? readInlineWord('ownerId', text), lifetimeRegionId: readInlineWord('lifetime', text) ?? readInlineWord('lifetimeRegion', text) ?? readInlineWord('lifetimeRegionId', text), mode: readInlineWord('mode', text) ?? 'unknown', access: readInlineWord('access', text) });
@@ -103,18 +122,28 @@ function parseResourceRecord(kind, name, text, graph) {
103
122
  if (kind === 'lifetimeRelation') return cleanRecord({ ...common, relationKind: readInlineWord('relationKind', text) ?? readInlineWord('kind', text) ?? 'outlives', fromLifetimeId: readInlineWord('fromLifetime', text) ?? readInlineWord('fromLifetimeId', text) ?? readInlineWord('from', text), toLifetimeId: readInlineWord('toLifetime', text) ?? readInlineWord('toLifetimeId', text) ?? readInlineWord('to', text), from: readInlineWord('from', text), to: readInlineWord('to', text) });
104
123
  if (kind === 'borrowScope') return cleanRecord({ ...common, scopeKind: readInlineWord('scopeKind', text) ?? readInlineWord('kind', text) ?? 'borrow-scope', constraintKind: readInlineWord('constraintKind', text), constraintKinds: readInlineList(text, 'constraint', 'constraints', 'constraintKind', 'constraintKinds') ?? [], ownershipKind: readInlineWord('ownershipKind', text), lifetimeKind: readInlineWord('lifetimeKind', text), controlFlowKind: readInlineWord('controlFlowKind', text), sourceControlFlowId: readInlineWord('sourceControlFlow', text) ?? readInlineWord('sourceControlFlowId', text), lifetimeRegionId: readInlineWord('lifetime', text) ?? readInlineWord('lifetimeRegion', text) ?? readInlineWord('lifetimeRegionId', text), resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text) });
105
124
  if (kind === 'unsafeBoundary') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), unsafeBoundary: true, proofStatus: readInlineWord('proofStatus', text) ?? readInlineWord('status', text) ?? 'missing', kind: readInlineWord('kind', text) });
125
+ const lowLevelRecord = parseLowLevelResourceRecord(kind, common, name, text);
126
+ if (lowLevelRecord) return lowLevelRecord;
106
127
  if (kind === 'conflict') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), ownerId: readInlineWord('owner', text) ?? readInlineWord('ownerId', text), loanId: readInlineWord('loan', text) ?? readInlineWord('loanId', text), aliasId: readInlineWord('alias', text) ?? readInlineWord('aliasId', text), unsafeBoundaryId: readInlineWord('unsafeBoundary', text) ?? readInlineWord('unsafeBoundaryId', text), reasonCode: readInlineWord('reasonCode', text), message: readInlineQuoted('message', text), status: readInlineWord('status', text) ?? 'open', severity: readInlineWord('severity', text) ?? 'error' });
107
128
  if (kind === 'proofObligation') return cleanRecord({ ...common, resourceId: readInlineWord('resource', text) ?? readInlineWord('resourceId', text), conflictId: readInlineWord('conflict', text) ?? readInlineWord('conflictId', text), kind: readInlineWord('kind', text), status: readInlineWord('status', text) ?? 'open', statement: readInlineQuoted('statement', text) });
108
129
  return undefined;
109
130
  }
110
131
 
111
- function commonRecord(kind, name, text, graph) {
132
+ function commonRecord(kind, name, text, graph, authoredLine = {}) {
112
133
  return cleanRecord({
113
134
  recordKind: recordKind(kind),
114
135
  id: idFrom(text, `${recordPrefix(kind)}_${name}`),
115
136
  name,
116
137
  sourcePath: readInlineWord('sourcePath', text) ?? readInlineWord('path', text) ?? graph.sourcePath,
117
138
  sourceHash: readInlineWord('sourceHash', text) ?? graph.sourceHash,
139
+ sourceSpan: authoredLine.sourceSpan,
140
+ authoredSourceSpan: authoredLine.sourceSpan,
141
+ sourceMapIds: readInlineList(text, 'sourceMap', 'sourceMaps', 'sourceMapId', 'sourceMapIds'),
142
+ sourceMapMappingIds: readInlineList(text, 'sourceMapMapping', 'sourceMapMappings', 'sourceMapMappingId', 'sourceMapMappingIds'),
143
+ proofEvidenceIds: readInlineList(text, 'proofEvidence', 'proofEvidenceId', 'proofEvidenceIds'),
144
+ proofObligationIds: readInlineList(text, 'proofObligation', 'proofObligations', 'proofObligationId', 'proofObligationIds', 'obligation', 'obligations'),
145
+ missingEvidence: readInlineList(text, 'missingEvidence'),
146
+ failClosed: readInlineFlag('failClosed', text),
118
147
  evidenceIds: readInlineList(text, 'evidence', 'evidenceIds') ?? graph.evidenceIds,
119
148
  metadata: { authoredName: name }
120
149
  });
@@ -134,11 +163,22 @@ function summarize(graph) {
134
163
  lifetimeRelations: graph.lifetimeRelations.length,
135
164
  borrowScopes: graph.borrowScopes.length,
136
165
  unsafeBoundaries: graph.unsafeBoundaries.length,
166
+ memoryRegions: graph.memoryRegions.length,
167
+ dataLayouts: graph.dataLayouts.length,
168
+ pointerEdges: graph.pointerEdges.length,
169
+ memoryAccesses: graph.memoryAccesses.length,
170
+ abiBoundaries: graph.abiBoundaries.length,
171
+ traps: graph.traps.length,
172
+ undefinedBehaviors: graph.undefinedBehaviors.length,
173
+ lowLevelPrimitives: graph.memoryRegions.length + graph.dataLayouts.length + graph.pointerEdges.length + graph.memoryAccesses.length + graph.abiBoundaries.length + graph.traps.length + graph.undefinedBehaviors.length,
137
174
  conflicts: graph.conflicts.length,
138
175
  proofObligations: graph.proofObligations.length,
139
176
  unsafeBoundariesWithoutProof: graph.unsafeBoundaries.filter((record) => record.proofStatus !== 'passed').length,
177
+ failClosedTraps: graph.traps.filter((record) => record.failClosed).length,
178
+ trapsWithoutProof: graph.traps.filter((record) => record.proofStatus !== 'passed').length,
179
+ undefinedBehaviorsWithoutProof: graph.undefinedBehaviors.filter((record) => record.proofStatus !== 'passed').length,
140
180
  parseErrors: graph.parser?.errors?.length ?? 0,
141
- reasonCodes: unique(graph.conflicts.map((record) => record.reasonCode))
181
+ reasonCodes: unique([...graph.conflicts, ...graph.traps, ...graph.undefinedBehaviors].map((record) => record.reasonCode))
142
182
  };
143
183
  }
144
184
 
@@ -155,6 +195,13 @@ function allRecords(graph) {
155
195
  ...graph.lifetimeRelations,
156
196
  ...graph.borrowScopes,
157
197
  ...graph.unsafeBoundaries,
198
+ ...graph.memoryRegions,
199
+ ...graph.dataLayouts,
200
+ ...graph.pointerEdges,
201
+ ...graph.memoryAccesses,
202
+ ...graph.abiBoundaries,
203
+ ...graph.traps,
204
+ ...graph.undefinedBehaviors,
158
205
  ...graph.conflicts,
159
206
  ...graph.proofObligations
160
207
  ];
@@ -165,6 +212,13 @@ function normalizeRowKind(kind) {
165
212
  if (kind === 'outlives' || kind === 'lifetimeRelation' || kind === 'lifeRelation') return 'lifetimeRelation';
166
213
  if (kind === 'borrow' || kind === 'borrowScope' || kind === 'borrowRegion') return 'borrowScope';
167
214
  if (kind === 'unsafe' || kind === 'unsafeBoundary') return 'unsafeBoundary';
215
+ if (kind === 'memory' || kind === 'memoryRegion' || kind === 'region') return 'memoryRegion';
216
+ if (kind === 'layout' || kind === 'dataLayout') return 'dataLayout';
217
+ if (kind === 'pointer' || kind === 'ptr' || kind === 'address') return 'pointerEdge';
218
+ if (kind === 'access' || kind === 'memoryAccess' || kind === 'atomic' || kind === 'volatile') return 'memoryAccess';
219
+ if (kind === 'abi' || kind === 'abiBoundary' || kind === 'callBoundary') return 'abiBoundary';
220
+ if (kind === 'traps') return 'trap';
221
+ if (kind === 'undefined' || kind === 'ub' || kind === 'undefinedBehavior' || kind === 'undefinedBehaviour') return 'undefinedBehavior';
168
222
  if (kind === 'proof' || kind === 'obligation' || kind === 'proofObligation') return 'proofObligation';
169
223
  return kind;
170
224
  }
@@ -174,6 +228,12 @@ function recordKind(kind) {
174
228
  if (kind === 'lifetimeRelation') return 'lifetime-relation';
175
229
  if (kind === 'borrowScope') return 'borrow-scope';
176
230
  if (kind === 'unsafeBoundary') return 'unsafe-boundary';
231
+ if (kind === 'memoryRegion') return 'memory-region';
232
+ if (kind === 'dataLayout') return 'data-layout';
233
+ if (kind === 'pointerEdge') return 'pointer-edge';
234
+ if (kind === 'memoryAccess') return 'memory-access';
235
+ if (kind === 'abiBoundary') return 'abi-boundary';
236
+ if (kind === 'undefinedBehavior') return 'undefined-behavior';
177
237
  if (kind === 'proofObligation') return 'proof-obligation';
178
238
  return kind;
179
239
  }
@@ -195,6 +255,7 @@ function readListLine(label, body) {
195
255
  }
196
256
  function readInlineWord(label, text) { return new RegExp('(?:^|\\s)' + label + '\\s+([^\\s,]+)').exec(text)?.[1]?.trim(); }
197
257
  function readInlineQuoted(label, text) { return new RegExp("(?:^|\\s)" + label + "\\s+[\"']([^\"']+)[\"']").exec(text)?.[1]?.trim(); }
258
+ function readInlineFlag(label, text) { return new RegExp('(?:^|\\s)' + label + '(?:\\s|$)').test(text) || undefined; }
198
259
  function readInlineNumber(label, text) {
199
260
  const value = readInlineWord(label, text);
200
261
  return value === undefined ? undefined : Number(value);
@@ -208,6 +269,21 @@ function readInlineList(text, ...labels) {
208
269
  }
209
270
  function ids(records = []) { return records.map((record) => record?.id).filter(Boolean); }
210
271
  function unique(values = []) { return [...new Set(values.filter(Boolean))]; }
272
+ function readAuthoredLines(block) {
273
+ const lines = block.body.split('\n');
274
+ const records = [];
275
+ let lineStart = block.syntax?.bodyStartOffset ?? 0;
276
+ for (const rawLine of lines) {
277
+ const rawEnd = lineStart + rawLine.length;
278
+ const leading = /^\s*/.exec(rawLine)?.[0].length ?? 0;
279
+ const trailing = /\s*$/.exec(rawLine)?.[0].length ?? 0;
280
+ const startOffset = lineStart + leading;
281
+ const endOffset = Math.max(startOffset, rawEnd - trailing);
282
+ records.push({ text: rawLine.trim(), sourceSpan: typeof block.sourceSpan === 'function' ? block.sourceSpan(startOffset, endOffset) : undefined });
283
+ lineStart = rawEnd + 1;
284
+ }
285
+ return records;
286
+ }
211
287
  function cleanRecord(record) {
212
288
  return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined && (!Array.isArray(value) || value.length > 0)));
213
289
  }
@@ -16,8 +16,8 @@ export const ROW_SYNTAX_CONFIG = Object.freeze({
16
16
  runtimeCapabilities: rowConfig('runtimeCapabilityRow', 'runtime_capability_row', runtimeRows, normalizeRuntimeCapabilityRow),
17
17
  runtimeCapabilityMatrix: rowConfig('runtimeCapabilityRow', 'runtime_capability_row', runtimeRows, normalizeRuntimeCapabilityRow),
18
18
  runtimeHosts: rowConfig('runtimeCapabilityRow', 'runtime_capability_row', runtimeRows, normalizeRuntimeCapabilityRow),
19
- resourceGraph: rowConfig('resourceGraphRow', 'resource_graph_row', words('resource owner loan alias move drop escape lifetime lifetimeRegion life outlives lifetimeRelation lifeRelation borrow borrowScope borrowRegion unsafe unsafeBoundary conflict proof proofObligation obligation'), normalizeResourceGraphRow),
20
- semanticResourceGraph: rowConfig('resourceGraphRow', 'resource_graph_row', words('resource owner loan alias move drop escape lifetime lifetimeRegion life outlives lifetimeRelation lifeRelation borrow borrowScope borrowRegion unsafe unsafeBoundary conflict proof proofObligation obligation'), normalizeResourceGraphRow),
19
+ resourceGraph: rowConfig('resourceGraphRow', 'resource_graph_row', words('resource owner loan alias move drop escape lifetime lifetimeRegion life outlives lifetimeRelation lifeRelation borrow borrowScope borrowRegion unsafe unsafeBoundary memory memoryRegion region layout dataLayout pointer ptr address access memoryAccess atomic volatile abi abiBoundary callBoundary trap traps undefined undefinedBehavior undefinedBehaviour ub conflict proof proofObligation obligation'), normalizeResourceGraphRow),
20
+ semanticResourceGraph: rowConfig('resourceGraphRow', 'resource_graph_row', words('resource owner loan alias move drop escape lifetime lifetimeRegion life outlives lifetimeRelation lifeRelation borrow borrowScope borrowRegion unsafe unsafeBoundary memory memoryRegion region layout dataLayout pointer ptr address access memoryAccess atomic volatile abi abiBoundary callBoundary trap traps undefined undefinedBehavior undefinedBehaviour ub conflict proof proofObligation obligation'), normalizeResourceGraphRow),
21
21
  applicationSurface: rowConfig('applicationSurfaceRow', 'application_surface_row', appRows, normalizeApplicationSurfaceRow),
22
22
  appHost: rowConfig('applicationSurfaceRow', 'application_surface_row', appRows, normalizeApplicationSurfaceRow),
23
23
  plugin: rowConfig('applicationSurfaceRow', 'application_surface_row', appRows, normalizeApplicationSurfaceRow),
@@ -79,6 +79,13 @@ function normalizeResourceGraphRow(rowKind) {
79
79
  if (rowKind === 'lifeRelation') return 'lifetimeRelation';
80
80
  if (rowKind === 'borrowRegion') return 'borrowScope';
81
81
  if (rowKind === 'unsafe') return 'unsafeBoundary';
82
+ if (rowKind === 'memory' || rowKind === 'region') return 'memoryRegion';
83
+ if (rowKind === 'layout') return 'dataLayout';
84
+ if (rowKind === 'pointer' || rowKind === 'ptr' || rowKind === 'address') return 'pointerEdge';
85
+ if (rowKind === 'access' || rowKind === 'atomic' || rowKind === 'volatile') return 'memoryAccess';
86
+ if (rowKind === 'abi' || rowKind === 'callBoundary') return 'abiBoundary';
87
+ if (rowKind === 'traps') return 'trap';
88
+ if (rowKind === 'undefined' || rowKind === 'undefinedBehaviour' || rowKind === 'ub') return 'undefinedBehavior';
82
89
  if (rowKind === 'proof' || rowKind === 'proofObligation') return 'obligation';
83
90
  return rowKind;
84
91
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-parser",
3
- "version": "0.3.71",
3
+ "version": "0.3.73",
4
4
  "description": "Parser for the first Frontier Lang .frontier syntax slice.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",