@shapeshift-labs/frontier-lang-compiler 0.2.26 → 0.2.27

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 CHANGED
@@ -333,6 +333,7 @@ Use injected parser adapters when a real language parser is available but should
333
333
  import {
334
334
  createBabelNativeImporterAdapter,
335
335
  createPythonAstNativeImporterAdapter,
336
+ createRustSynNativeImporterAdapter,
336
337
  importNativeProject,
337
338
  runNativeImporterAdapter
338
339
  } from '@shapeshift-labs/frontier-lang-compiler';
@@ -343,6 +344,10 @@ const babelAdapter = createBabelNativeImporterAdapter({
343
344
  const pythonAstAdapter = createPythonAstNativeImporterAdapter({
344
345
  parserModule: hostPythonAstParser
345
346
  });
347
+ const rustSynAdapter = createRustSynNativeImporterAdapter({
348
+ parserModule: hostRustSynParser,
349
+ rustEdition: '2021'
350
+ });
346
351
 
347
352
  const imported = await runNativeImporterAdapter(babelAdapter, {
348
353
  sourcePath: 'src/todo.ts',
@@ -351,10 +356,11 @@ const imported = await runNativeImporterAdapter(babelAdapter, {
351
356
 
352
357
  const project = await importNativeProject({
353
358
  projectRoot: 'src',
354
- adapters: [babelAdapter, pythonAstAdapter],
359
+ adapters: [babelAdapter, pythonAstAdapter, rustSynAdapter],
355
360
  sources: [
356
361
  { language: 'typescript', adapter: babelAdapter.id, sourcePath: 'src/todo.ts', sourceText },
357
- { language: 'python', adapter: pythonAstAdapter.id, sourcePath: 'tools/todo.py', sourceText: pythonSource }
362
+ { language: 'python', adapter: pythonAstAdapter.id, sourcePath: 'tools/todo.py', sourceText: pythonSource },
363
+ { language: 'rust', adapter: rustSynAdapter.id, sourcePath: 'src/todo.rs', sourceText: rustSource }
358
364
  ]
359
365
  });
360
366
 
@@ -374,6 +380,7 @@ The built-in adapter factories are dependency-light wrappers for caller-owned pa
374
380
  - `createBabelNativeImporterAdapter`
375
381
  - `createTypeScriptCompilerNativeImporterAdapter`
376
382
  - `createPythonAstNativeImporterAdapter`
383
+ - `createRustSynNativeImporterAdapter`
377
384
  - `createTreeSitterNativeImporterAdapter`
378
385
 
379
386
  Adapter summaries include a structured `coverage` record so merge queues can distinguish exact parser AST imports from declaration scans. The record declares exactness, parser token/trivia support, diagnostics support, source-range and generated-range support, and semantic coverage. Built-in wrappers normalize native AST/CST nodes and declaration-level semantic indexes; they do not claim resolved references, types, control flow, generated ranges, or token/trivia fidelity unless the host adapter supplies that evidence.
package/bench/smoke.mjs CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  createProjectionTargetLossMatrix,
9
9
  createNativeSourcePreservation,
10
10
  createPythonAstNativeImporterAdapter,
11
+ createRustSynNativeImporterAdapter,
11
12
  createSemanticImportSidecar,
12
13
  diffNativeSources,
13
14
  importExternalSemanticIndex,
@@ -78,7 +79,7 @@ const matrixDurationMs = performance.now() - matrixStart;
78
79
  const parserFormatMatrixStart = performance.now();
79
80
  const parserFormatMatrix = createNativeParserAstFormatMatrix({
80
81
  imports: nativeImportResults,
81
- adapters: [estreeAdapter, createPythonAstNativeImporterAdapter()]
82
+ adapters: [estreeAdapter, createPythonAstNativeImporterAdapter(), createRustSynNativeImporterAdapter()]
82
83
  });
83
84
  const parserFormatMatrixDurationMs = performance.now() - parserFormatMatrixStart;
84
85
 
package/dist/index.d.ts CHANGED
@@ -1388,6 +1388,28 @@ export interface PythonAstNativeImporterAdapterOptions {
1388
1388
  readonly maxNodes?: number;
1389
1389
  }
1390
1390
 
1391
+ export interface RustSynNativeImporterAdapterOptions {
1392
+ readonly id?: string;
1393
+ readonly language?: FrontierSourceLanguage;
1394
+ readonly parser?: string;
1395
+ readonly version?: string;
1396
+ readonly capabilities?: readonly string[];
1397
+ readonly coverage?: NativeImporterAdapterCoverageInput;
1398
+ readonly supportedExtensions?: readonly string[];
1399
+ readonly diagnostics?: readonly NativeImporterAdapterDiagnostic[];
1400
+ readonly ast?: unknown;
1401
+ readonly file?: unknown;
1402
+ readonly sourceFile?: unknown;
1403
+ readonly parse?: (sourceText: string, options: Record<string, unknown>) => unknown;
1404
+ readonly parserModule?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1405
+ readonly rustSyn?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1406
+ readonly syn?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1407
+ readonly parserOptions?: Record<string, unknown>;
1408
+ readonly rustEdition?: '2015' | '2018' | '2021' | '2024' | string;
1409
+ readonly includeAttributes?: boolean;
1410
+ readonly maxNodes?: number;
1411
+ }
1412
+
1391
1413
  export interface TreeSitterNativeImporterAdapterOptions {
1392
1414
  readonly id?: string;
1393
1415
  readonly language?: FrontierSourceLanguage;
@@ -1758,6 +1780,7 @@ export declare function createEstreeNativeImporterAdapter(options?: JavaScriptNa
1758
1780
  export declare function createBabelNativeImporterAdapter(options?: JavaScriptNativeImporterAdapterOptions): NativeImporterAdapter;
1759
1781
  export declare function createTypeScriptCompilerNativeImporterAdapter(options?: TypeScriptCompilerNativeImporterAdapterOptions): NativeImporterAdapter;
1760
1782
  export declare function createPythonAstNativeImporterAdapter(options?: PythonAstNativeImporterAdapterOptions): NativeImporterAdapter;
1783
+ export declare function createRustSynNativeImporterAdapter(options?: RustSynNativeImporterAdapterOptions): NativeImporterAdapter;
1761
1784
  export declare function createTreeSitterNativeImporterAdapter(options?: TreeSitterNativeImporterAdapterOptions): NativeImporterAdapter;
1762
1785
  export declare function runNativeImporterAdapter(adapter: NativeImporterAdapter, input: RunNativeImporterAdapterOptions): Promise<NativeImporterAdapterImportResult>;
1763
1786
  export declare function runNativeTargetProjectionAdapter(adapter: NativeTargetProjectionAdapter, input: NativeTargetProjectionAdapterInput): NativeTargetProjectionResult;
package/dist/index.js CHANGED
@@ -378,6 +378,31 @@ export const NativeParserAstFormatProfiles = Object.freeze([
378
378
  supportsErrorRecovery: false,
379
379
  notes: ['Python stdlib AST exposes versioned abstract grammar and source locations, but not formatting trivia.']
380
380
  }),
381
+ nativeParserAstFormatProfile('rust-syn', {
382
+ aliases: ['syn'],
383
+ kind: 'abstract-ast',
384
+ languages: ['rust'],
385
+ parserAdapters: ['syn', 'rust-syn'],
386
+ exactness: 'exact-parser-ast',
387
+ sourceRangeModel: 'proc-macro2-span',
388
+ preservesTokens: false,
389
+ preservesTrivia: false,
390
+ supportsErrorRecovery: false,
391
+ notes: ['syn parses Rust token streams into an abstract syntax tree; macro expansion, name resolution, type checking, and lossless trivia remain host-owned evidence.']
392
+ }),
393
+ nativeParserAstFormatProfile('rust-analyzer-rowan', {
394
+ aliases: ['rowan', 'rust-analyzer'],
395
+ kind: 'concrete-syntax-tree',
396
+ languages: ['rust'],
397
+ parserAdapters: ['rust-analyzer-rowan'],
398
+ exactness: 'parser-tree',
399
+ sourceRangeModel: 'text-range',
400
+ preservesTokens: true,
401
+ preservesTrivia: true,
402
+ supportsIncremental: true,
403
+ supportsErrorRecovery: true,
404
+ notes: ['rust-analyzer uses rowan-backed concrete syntax trees with AST wrappers; semantic richness still depends on host analysis evidence.']
405
+ }),
381
406
  nativeParserAstFormatProfile('tree-sitter', {
382
407
  kind: 'concrete-syntax-tree',
383
408
  languages: ['mixed'],
@@ -2631,6 +2656,61 @@ export function createPythonAstNativeImporterAdapter(options = {}) {
2631
2656
  };
2632
2657
  }
2633
2658
 
2659
+ export function createRustSynNativeImporterAdapter(options = {}) {
2660
+ return {
2661
+ id: options.id ?? 'frontier.rust-syn-native-importer',
2662
+ language: options.language ?? 'rust',
2663
+ parser: options.parser ?? 'syn',
2664
+ version: options.version,
2665
+ capabilities: uniqueStrings(['nativeAst', 'semanticIndex', 'sourceMaps', 'diagnostics', ...(options.capabilities ?? [])]),
2666
+ coverage: nativeImporterAdapterCoverage({
2667
+ exactness: 'exact-parser-ast',
2668
+ exactAst: true,
2669
+ tokens: false,
2670
+ trivia: false,
2671
+ diagnostics: true,
2672
+ sourceRanges: false,
2673
+ generatedRanges: false,
2674
+ semanticCoverage: declarationSemanticCoverage(),
2675
+ notes: [
2676
+ 'Normalizes caller-owned syn-shaped Rust ASTs into native AST nodes and declaration-level semantic index records.',
2677
+ 'syn does not expand macros, resolve names, type-check, or preserve full concrete syntax/trivia; attach rust-analyzer/rustc evidence for those claims.'
2678
+ ]
2679
+ }, options.coverage),
2680
+ supportedExtensions: options.supportedExtensions ?? ['.rs'],
2681
+ diagnostics: options.diagnostics,
2682
+ parse(input) {
2683
+ const parsed = input.options?.ast
2684
+ ?? input.options?.nativeAst
2685
+ ?? input.options?.file
2686
+ ?? input.options?.sourceFile
2687
+ ?? options.ast
2688
+ ?? options.file
2689
+ ?? options.sourceFile
2690
+ ?? parseRustSynSource(input, options);
2691
+ const root = rustSynAstRoot(parsed);
2692
+ if (!root) {
2693
+ return missingInjectedParserResult(input, {
2694
+ parser: options.parser ?? 'syn',
2695
+ adapterId: options.id ?? 'frontier.rust-syn-native-importer',
2696
+ message: 'createRustSynNativeImporterAdapter requires an injected syn-shaped AST object, parserModule.parse function, parse function, or adapterOptions.ast.'
2697
+ });
2698
+ }
2699
+ const parseDiagnostics = normalizeParserErrors(parsed?.errors ?? parsed?.diagnostics, input, {
2700
+ parser: options.parser ?? 'syn'
2701
+ });
2702
+ return createNativeImportFromRustSyn(root, input, {
2703
+ parser: options.parser ?? 'syn',
2704
+ astFormat: 'rust-syn',
2705
+ maxNodes: options.maxNodes,
2706
+ diagnostics: parseDiagnostics,
2707
+ rustEdition: options.rustEdition ?? input.options?.rustEdition ?? parsed?.rustEdition,
2708
+ includeAttributes: options.includeAttributes ?? input.options?.includeAttributes
2709
+ });
2710
+ }
2711
+ };
2712
+ }
2713
+
2634
2714
  export function createTreeSitterNativeImporterAdapter(options = {}) {
2635
2715
  return {
2636
2716
  id: options.id ?? `frontier.tree-sitter-${idFragment(options.language ?? 'source')}-native-importer`,
@@ -7069,6 +7149,8 @@ function parserAstFormatIdForParser(parser) {
7069
7149
  const text = normalizeParserAstFormatId(parser);
7070
7150
  if (text.includes('typescript')) return 'typescript-compiler-api';
7071
7151
  if (text.includes('python') && text.includes('ast')) return 'python-ast';
7152
+ if (text === 'syn' || text.includes('rust-syn')) return 'rust-syn';
7153
+ if (text.includes('rust-analyzer') || text.includes('rowan')) return 'rust-analyzer-rowan';
7072
7154
  if (text.includes('tree-sitter') || text.includes('treesitter')) return 'tree-sitter';
7073
7155
  if (text.includes('babel')) return 'babel';
7074
7156
  if (text.includes('estree')) return 'estree';
@@ -8103,6 +8185,20 @@ function parsePythonAstSource(input, options) {
8103
8185
  return parse(input.sourceText, parserOptions);
8104
8186
  }
8105
8187
 
8188
+ function parseRustSynSource(input, options) {
8189
+ const parse = options.parse ?? options.parserModule?.parse ?? options.rustSyn?.parse ?? options.syn?.parse;
8190
+ if (typeof parse !== 'function') return undefined;
8191
+ const parserOptions = {
8192
+ sourcePath: input.sourcePath,
8193
+ filename: input.sourcePath,
8194
+ edition: options.rustEdition ?? input.options?.rustEdition ?? '2021',
8195
+ includeAttributes: options.includeAttributes ?? input.options?.includeAttributes,
8196
+ ...(options.parserOptions ?? {}),
8197
+ ...(input.options?.parserOptions ?? {})
8198
+ };
8199
+ return parse(input.sourceText, parserOptions);
8200
+ }
8201
+
8106
8202
  function createNativeImportFromSyntaxAst(ast, input, options) {
8107
8203
  const root = normalizeSyntaxAstRoot(ast, options.astFormat);
8108
8204
  if (!root) {
@@ -8193,6 +8289,36 @@ function createNativeImportFromPythonAst(root, input, options) {
8193
8289
  };
8194
8290
  }
8195
8291
 
8292
+ function createNativeImportFromRustSyn(root, input, options) {
8293
+ const context = createAstNormalizationContext(input, options);
8294
+ visitRustSynNode(root, context, 'root');
8295
+ if (context.truncated) {
8296
+ context.losses.push(truncatedAstLoss(input, context, options));
8297
+ }
8298
+ const semantic = semanticIndexFromNativeDeclarations(context.declarations, input, options);
8299
+ return {
8300
+ rootId: context.rootId,
8301
+ nodes: context.nodes,
8302
+ semanticIndex: semantic.semanticIndex,
8303
+ mappings: semantic.mappings,
8304
+ losses: mergeNativeLosses(context.losses, options.diagnostics?.map((diagnostic, index) => adapterDiagnosticToLoss(diagnostic, index, {
8305
+ id: input.adapterId,
8306
+ version: input.adapterVersion
8307
+ }, input)) ?? []),
8308
+ evidence: semantic.evidence,
8309
+ diagnostics: options.diagnostics,
8310
+ metadata: {
8311
+ astFormat: options.astFormat,
8312
+ parser: options.parser,
8313
+ rustEdition: options.rustEdition,
8314
+ includeAttributes: Boolean(options.includeAttributes),
8315
+ normalizedNodeCount: Object.keys(context.nodes).length,
8316
+ declarationCount: context.declarations.length,
8317
+ truncated: context.truncated
8318
+ }
8319
+ };
8320
+ }
8321
+
8196
8322
  function createNativeImportFromTreeSitter(root, input, options) {
8197
8323
  const context = createAstNormalizationContext(input, options);
8198
8324
  visitTreeSitterNode(root, context, 'root');
@@ -8376,6 +8502,67 @@ function visitPythonAstNode(node, context, propertyPath) {
8376
8502
  return id;
8377
8503
  }
8378
8504
 
8505
+ function visitRustSynNode(node, context, propertyPath) {
8506
+ if (!isRustSynAstNode(node) || context.truncated) return undefined;
8507
+ if (context.objectIds.has(node)) return context.objectIds.get(node);
8508
+ if (context.counter >= context.maxNodes) {
8509
+ context.truncated = true;
8510
+ return undefined;
8511
+ }
8512
+ const kind = rustSynKind(node);
8513
+ const payload = rustSynPayload(node);
8514
+ const span = spanFromRustSynNode(payload, context.input);
8515
+ const id = nativeNodeId(context, kind, { start: { line: span?.startLine, column: span?.startColumn } }, propertyPath);
8516
+ context.objectIds.set(node, id);
8517
+ if (!context.rootId) context.rootId = id;
8518
+ const children = [];
8519
+ for (const [field, value] of rustSynChildEntries(node)) {
8520
+ if (Array.isArray(value)) {
8521
+ value.forEach((entry, index) => {
8522
+ const childId = visitRustSynNode(entry, context, `${propertyPath}.${field}[${index}]`);
8523
+ if (childId) children.push(childId);
8524
+ });
8525
+ } else {
8526
+ const childId = visitRustSynNode(value, context, `${propertyPath}.${field}`);
8527
+ if (childId) children.push(childId);
8528
+ }
8529
+ }
8530
+ const declaration = rustSynDeclaration(payload, kind, id, context.input);
8531
+ const nativeNode = {
8532
+ id,
8533
+ kind,
8534
+ languageKind: `${context.input.language}.${kind}`,
8535
+ span,
8536
+ value: declaration?.name ?? rustSynNodeValue(payload),
8537
+ fields: primitiveRustSynFields(payload, kind),
8538
+ children,
8539
+ metadata: {
8540
+ astFormat: context.options.astFormat,
8541
+ propertyPath,
8542
+ spanKind: rustSynSpanKind(payload)
8543
+ }
8544
+ };
8545
+ context.nodes[id] = nativeNode;
8546
+ if (declaration) context.declarations.push({ ...declaration, nativeNode });
8547
+ if (rustSynMacroKind(kind)) {
8548
+ context.losses.push({
8549
+ id: `loss_${idFragment(id)}_rust_macro_expansion`,
8550
+ severity: 'warning',
8551
+ phase: 'parse',
8552
+ sourceFormat: context.input.language,
8553
+ kind: 'macroExpansion',
8554
+ message: 'Rust macro syntax was parsed but macro expansion and generated items require host compiler evidence.',
8555
+ span,
8556
+ nodeId: id,
8557
+ metadata: {
8558
+ parser: context.options.parser,
8559
+ astFormat: context.options.astFormat
8560
+ }
8561
+ });
8562
+ }
8563
+ return id;
8564
+ }
8565
+
8379
8566
  function visitTreeSitterNode(node, context, propertyPath) {
8380
8567
  if (!node || typeof node !== 'object' || context.truncated) return undefined;
8381
8568
  if (context.objectIds.has(node)) return context.objectIds.get(node);
@@ -9530,6 +9717,87 @@ function pythonAstKind(node) {
9530
9717
  return node?._type ?? node?.type ?? node?.kind ?? node?.nodeType;
9531
9718
  }
9532
9719
 
9720
+ function rustSynAstRoot(value) {
9721
+ if (!value || typeof value !== 'object') return undefined;
9722
+ if (isRustSynAstNode(value)) return value;
9723
+ if (isRustSynAstNode(value.ast)) return value.ast;
9724
+ if (isRustSynAstNode(value.file)) return value.file;
9725
+ if (isRustSynAstNode(value.root)) return value.root;
9726
+ if (isRustSynAstNode(value.module)) return value.module;
9727
+ if (isRustSynAstNode(value.sourceFile)) return value.sourceFile;
9728
+ return undefined;
9729
+ }
9730
+
9731
+ function isRustSynAstNode(value) {
9732
+ return Boolean(value && typeof value === 'object' && typeof rustSynKind(value) === 'string');
9733
+ }
9734
+
9735
+ function rustSynKind(node) {
9736
+ const declared = node?._type ?? node?.type ?? node?.kind ?? node?.nodeType ?? node?.synKind;
9737
+ if (typeof declared === 'string') return normalizeRustSynKind(declared);
9738
+ const wrapper = rustSynWrapperKind(node);
9739
+ if (wrapper) return normalizeRustSynKind(wrapper);
9740
+ if (Array.isArray(node?.items)) return 'File';
9741
+ if (node?.sig && node?.block) return 'ItemFn';
9742
+ if (node?.ident && node?.fields && Array.isArray(node?.variants)) return 'ItemEnum';
9743
+ if (node?.ident && node?.fields) return 'ItemStruct';
9744
+ if (node?.ident && Array.isArray(node?.items)) return 'ItemMod';
9745
+ if (node?.trait_ || node?.self_ty || node?.selfType) return 'ItemImpl';
9746
+ if (node?.path && (node?.tree || node?.trees)) return 'ItemUse';
9747
+ return undefined;
9748
+ }
9749
+
9750
+ function rustSynPayload(node) {
9751
+ if (!node || typeof node !== 'object') return node;
9752
+ const wrapper = rustSynWrapperKind(node);
9753
+ return wrapper ? node[wrapper] : node;
9754
+ }
9755
+
9756
+ function rustSynWrapperKind(node) {
9757
+ if (!node || typeof node !== 'object') return undefined;
9758
+ const keys = Object.keys(node).filter((key) => !ignoredRustSynField(key));
9759
+ if (keys.length !== 1) return undefined;
9760
+ const key = keys[0];
9761
+ const value = node[key];
9762
+ if (!value || typeof value !== 'object') return undefined;
9763
+ if (/^(?:Fn|Struct|Enum|Trait|Impl|Use|Mod|Type|Const|Static|Union|Macro)$/.test(key)) return key;
9764
+ if (/^(?:Item|ImplItem|TraitItem|ForeignItem)/.test(key)) return key;
9765
+ return undefined;
9766
+ }
9767
+
9768
+ function normalizeRustSynKind(kind) {
9769
+ const text = String(kind);
9770
+ const compact = text.replace(/^(?:syn::)?/, '').replace(/^Item::/, 'Item').replace(/^ImplItem::/, 'ImplItem').replace(/^TraitItem::/, 'TraitItem');
9771
+ if (/^fn$/i.test(compact)) return 'ItemFn';
9772
+ if (/^struct$/i.test(compact)) return 'ItemStruct';
9773
+ if (/^enum$/i.test(compact)) return 'ItemEnum';
9774
+ if (/^trait$/i.test(compact)) return 'ItemTrait';
9775
+ if (/^impl$/i.test(compact)) return 'ItemImpl';
9776
+ if (/^use$/i.test(compact)) return 'ItemUse';
9777
+ if (/^mod$/i.test(compact)) return 'ItemMod';
9778
+ if (/^type$/i.test(compact)) return 'ItemType';
9779
+ if (/^const$/i.test(compact)) return 'ItemConst';
9780
+ if (/^static$/i.test(compact)) return 'ItemStatic';
9781
+ if (/^union$/i.test(compact)) return 'ItemUnion';
9782
+ if (/^item_fn$/i.test(compact)) return 'ItemFn';
9783
+ if (/^item_struct$/i.test(compact)) return 'ItemStruct';
9784
+ if (/^item_enum$/i.test(compact)) return 'ItemEnum';
9785
+ if (/^item_trait$/i.test(compact)) return 'ItemTrait';
9786
+ if (/^item_impl$/i.test(compact)) return 'ItemImpl';
9787
+ if (/^item_use$/i.test(compact)) return 'ItemUse';
9788
+ if (/^item_mod$/i.test(compact)) return 'ItemMod';
9789
+ if (/^item_type$/i.test(compact)) return 'ItemType';
9790
+ if (/^item_const$/i.test(compact)) return 'ItemConst';
9791
+ if (/^item_static$/i.test(compact)) return 'ItemStatic';
9792
+ if (/^item_union$/i.test(compact)) return 'ItemUnion';
9793
+ if (/^item_macro$/i.test(compact)) return 'ItemMacro';
9794
+ if (/^macro$/i.test(compact)) return 'Macro';
9795
+ if (/^impl_item_fn$/i.test(compact)) return 'ImplItemFn';
9796
+ if (/^trait_item_fn$/i.test(compact)) return 'TraitItemFn';
9797
+ if (/^foreign_item_fn$/i.test(compact)) return 'ForeignItemFn';
9798
+ return compact;
9799
+ }
9800
+
9533
9801
  function ignoredSyntaxField(key) {
9534
9802
  return key === 'type'
9535
9803
  || key === 'kind'
@@ -9564,6 +9832,18 @@ function ignoredPythonAstField(key) {
9564
9832
  || key === 'parent';
9565
9833
  }
9566
9834
 
9835
+ function ignoredRustSynField(key) {
9836
+ return key === '_type'
9837
+ || key === 'type'
9838
+ || key === 'kind'
9839
+ || key === 'nodeType'
9840
+ || key === 'synKind'
9841
+ || key === 'span'
9842
+ || key === 'tokens'
9843
+ || key === 'tokenStream'
9844
+ || key === 'parent';
9845
+ }
9846
+
9567
9847
  function primitiveSyntaxFields(node) {
9568
9848
  const fields = {};
9569
9849
  for (const key of ['name', 'operator', 'sourceType', 'async', 'generator', 'computed', 'static', 'exportKind', 'importKind', 'optional']) {
@@ -9595,6 +9875,22 @@ function primitivePythonAstFields(node, kind) {
9595
9875
  return fields;
9596
9876
  }
9597
9877
 
9878
+ function primitiveRustSynFields(node, kind) {
9879
+ const fields = { kind };
9880
+ const ident = rustSynIdentName(node.ident ?? node.name ?? node.sig?.ident);
9881
+ if (ident) fields.ident = ident;
9882
+ const path = rustSynPathName(node.path ?? node.trait_ ?? node.self_ty ?? node.selfType ?? node.ty);
9883
+ if (path) fields.path = path;
9884
+ const visibility = rustSynVisibility(node.vis ?? node.visibility);
9885
+ if (visibility) fields.visibility = visibility;
9886
+ for (const key of ['mutability', 'defaultness', 'constness', 'asyncness', 'unsafety', 'abi']) {
9887
+ const value = node[key];
9888
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value === null) fields[key] = value;
9889
+ }
9890
+ if (Array.isArray(node.attrs) && node.attrs.length) fields.attributeCount = node.attrs.length;
9891
+ return fields;
9892
+ }
9893
+
9598
9894
  function literalSyntaxValue(node) {
9599
9895
  if (node.value === null || typeof node.value === 'string' || typeof node.value === 'number' || typeof node.value === 'boolean') return node.value;
9600
9896
  return undefined;
@@ -9635,6 +9931,36 @@ function spanFromPythonAstNode(node, input) {
9635
9931
  };
9636
9932
  }
9637
9933
 
9934
+ function spanFromRustSynNode(node, input) {
9935
+ const span = node.span ?? node.ident?.span ?? node.sig?.ident?.span ?? node.name?.span;
9936
+ if (!span || typeof span !== 'object') return undefined;
9937
+ const start = span.start ?? span.lo ?? span.begin;
9938
+ const end = span.end ?? span.hi;
9939
+ const startLine = span.startLine ?? span.line ?? start?.line;
9940
+ const startColumn = span.startColumn ?? span.column ?? start?.column;
9941
+ const endLine = span.endLine ?? end?.line;
9942
+ const endColumn = span.endColumn ?? end?.column;
9943
+ if (typeof startLine !== 'number') return undefined;
9944
+ return {
9945
+ sourceId: input.sourceHash,
9946
+ path: input.sourcePath,
9947
+ startLine,
9948
+ startColumn: typeof startColumn === 'number' ? rustSynColumnToOneBased(startColumn, span) : undefined,
9949
+ endLine: typeof endLine === 'number' ? endLine : undefined,
9950
+ endColumn: typeof endColumn === 'number' ? rustSynColumnToOneBased(endColumn, span) : undefined
9951
+ };
9952
+ }
9953
+
9954
+ function rustSynColumnToOneBased(column, span) {
9955
+ return span.columnBase === 1 || span.columnsOneBased ? column : column + 1;
9956
+ }
9957
+
9958
+ function rustSynSpanKind(node) {
9959
+ const span = node.span ?? node.ident?.span ?? node.sig?.ident?.span ?? node.name?.span;
9960
+ if (!span || typeof span !== 'object') return undefined;
9961
+ return span.kind ?? span.source ?? 'host-span';
9962
+ }
9963
+
9638
9964
  function syntaxDeclaration(node, nativeNodeId, input) {
9639
9965
  const kind = String(node.type ?? node.kind ?? '');
9640
9966
  if (kind === 'ImportDeclaration') {
@@ -9671,6 +9997,46 @@ function pythonAstDeclaration(node, kind, nativeNodeId, input) {
9671
9997
  return undefined;
9672
9998
  }
9673
9999
 
10000
+ function rustSynDeclaration(node, kind, nativeNodeId, input) {
10001
+ if (kind === 'ItemUse' || kind === 'UseTree' || kind === 'UsePath' || kind === 'UseName') {
10002
+ const name = rustSynUseName(node);
10003
+ if (name) return declarationRecord(input, nativeNodeId, name, 'module', 'import');
10004
+ }
10005
+ if (kind === 'ItemFn' || kind === 'ForeignItemFn') {
10006
+ const name = rustSynIdentName(node.sig?.ident ?? node.ident ?? node.name);
10007
+ if (name) return declarationRecord(input, nativeNodeId, name, 'function', 'definition');
10008
+ }
10009
+ if (kind === 'ImplItemFn' || kind === 'TraitItemFn') {
10010
+ const name = rustSynIdentName(node.sig?.ident ?? node.ident ?? node.name);
10011
+ if (name) return declarationRecord(input, nativeNodeId, name, 'method', 'definition');
10012
+ }
10013
+ if (kind === 'ItemStruct' || kind === 'ItemUnion') {
10014
+ const name = rustSynIdentName(node.ident ?? node.name);
10015
+ if (name) return declarationRecord(input, nativeNodeId, name, 'class', 'definition');
10016
+ }
10017
+ if (kind === 'ItemEnum' || kind === 'ItemTrait' || kind === 'ItemType') {
10018
+ const name = rustSynIdentName(node.ident ?? node.name);
10019
+ if (name) return declarationRecord(input, nativeNodeId, name, 'type', 'definition');
10020
+ }
10021
+ if (kind === 'ItemMod') {
10022
+ const name = rustSynIdentName(node.ident ?? node.name);
10023
+ if (name) return declarationRecord(input, nativeNodeId, name, 'module', 'definition');
10024
+ }
10025
+ if (kind === 'ItemConst' || kind === 'ItemStatic') {
10026
+ const name = rustSynIdentName(node.ident ?? node.name);
10027
+ if (name) return declarationRecord(input, nativeNodeId, name, 'variable', 'definition');
10028
+ }
10029
+ if (kind === 'ItemImpl') {
10030
+ const name = rustSynImplName(node);
10031
+ if (name) return declarationRecord(input, nativeNodeId, name, 'type', 'definition');
10032
+ }
10033
+ if (rustSynMacroKind(kind)) {
10034
+ const name = rustSynIdentName(node.ident ?? node.mac?.path ?? node.path);
10035
+ if (name) return declarationRecord(input, nativeNodeId, name, 'macro', 'definition');
10036
+ }
10037
+ return undefined;
10038
+ }
10039
+
9674
10040
  function typeScriptDeclaration(node, kind, nativeNodeId, input) {
9675
10041
  if (kind === 'ImportDeclaration' || kind === 'ImportEqualsDeclaration') {
9676
10042
  const name = stringFromTsExpression(node.moduleSpecifier) ?? stringFromTsExpression(node.externalModuleReference?.expression);
@@ -9725,10 +10091,26 @@ function pythonAstChildEntries(node) {
9725
10091
  : isPythonAstNode(value));
9726
10092
  }
9727
10093
 
10094
+ function rustSynChildEntries(node) {
10095
+ const payload = rustSynPayload(node);
10096
+ const fieldNames = Object.keys(payload).filter((key) => !ignoredRustSynField(key));
10097
+ return fieldNames
10098
+ .map((field) => [field, payload[field]])
10099
+ .filter(([, value]) => Array.isArray(value)
10100
+ ? value.some(isRustSynAstNode)
10101
+ : isRustSynAstNode(value));
10102
+ }
10103
+
9728
10104
  function pythonAstNodeValue(node) {
9729
10105
  return node.name ?? node.id ?? node.arg ?? node.module ?? pythonAstLiteralValue(node);
9730
10106
  }
9731
10107
 
10108
+ function rustSynNodeValue(node) {
10109
+ return rustSynIdentName(node.ident ?? node.name ?? node.sig?.ident)
10110
+ ?? rustSynPathName(node.path ?? node.trait_ ?? node.self_ty ?? node.selfType ?? node.ty)
10111
+ ?? rustSynLiteralValue(node);
10112
+ }
10113
+
9732
10114
  function pythonAliasName(alias) {
9733
10115
  if (!alias) return undefined;
9734
10116
  if (typeof alias === 'string') return alias;
@@ -9757,6 +10139,96 @@ function pythonTargetName(target) {
9757
10139
  return undefined;
9758
10140
  }
9759
10141
 
10142
+ function rustSynIdentName(value) {
10143
+ if (!value) return undefined;
10144
+ if (typeof value === 'string') return value;
10145
+ if (typeof value.ident === 'string') return value.ident;
10146
+ if (typeof value.name === 'string') return value.name;
10147
+ if (typeof value.text === 'string') return value.text;
10148
+ if (typeof value.sym === 'string') return value.sym;
10149
+ if (typeof value.value === 'string') return value.value;
10150
+ if (typeof value.path === 'string') return value.path;
10151
+ return rustSynPathName(value.path ?? value);
10152
+ }
10153
+
10154
+ function rustSynPathName(value) {
10155
+ if (!value) return undefined;
10156
+ if (typeof value === 'string') return value;
10157
+ if (typeof value.ident === 'string') return value.ident;
10158
+ if (typeof value.name === 'string') return value.name;
10159
+ if (typeof value.path === 'string') return value.path;
10160
+ if (value.path && typeof value.path === 'object') return rustSynPathName(value.path);
10161
+ if (Array.isArray(value.segments)) {
10162
+ const names = value.segments
10163
+ .map((segment) => rustSynIdentName(segment.ident ?? segment))
10164
+ .filter(Boolean);
10165
+ return names.length ? names.join('::') : undefined;
10166
+ }
10167
+ if (Array.isArray(value.qself)) return value.qself.map(rustSynPathName).filter(Boolean).join('::');
10168
+ if (value.leading_colon && value.segments) {
10169
+ const name = rustSynPathName({ segments: value.segments });
10170
+ return name ? `::${name}` : undefined;
10171
+ }
10172
+ return undefined;
10173
+ }
10174
+
10175
+ function rustSynUseName(node) {
10176
+ if (!node) return undefined;
10177
+ if (node.prefix && node.tree) {
10178
+ const prefix = rustSynPathName(node.prefix);
10179
+ const child = rustSynUseName(node.tree);
10180
+ return [prefix, child].filter(Boolean).join('::') || undefined;
10181
+ }
10182
+ if (node.ident && node.tree) {
10183
+ const prefix = rustSynIdentName(node.ident);
10184
+ const child = rustSynUseName(node.tree);
10185
+ return [prefix, child].filter(Boolean).join('::') || undefined;
10186
+ }
10187
+ if (node.path && node.tree) {
10188
+ const prefix = rustSynPathName(node.path);
10189
+ const child = rustSynUseName(node.tree);
10190
+ return [prefix, child].filter(Boolean).join('::') || undefined;
10191
+ }
10192
+ if (Array.isArray(node.trees)) return node.trees.map(rustSynUseName).find(Boolean);
10193
+ if (node.tree) return rustSynUseName(node.tree);
10194
+ if (node.path) return rustSynPathName(node.path);
10195
+ if (node.name) return rustSynIdentName(node.name);
10196
+ if (node.ident) return rustSynIdentName(node.ident);
10197
+ if (node.rename) return rustSynIdentName(node.rename);
10198
+ return undefined;
10199
+ }
10200
+
10201
+ function rustSynImplName(node) {
10202
+ const selfType = rustSynPathName(node.self_ty ?? node.selfType ?? node.ty);
10203
+ const traitPath = Array.isArray(node.trait_)
10204
+ ? rustSynPathName(node.trait_[1] ?? node.trait_[0])
10205
+ : rustSynPathName(node.trait_);
10206
+ if (selfType && traitPath) return `${selfType}.${traitPath}.impl`;
10207
+ if (selfType) return `${selfType}.impl`;
10208
+ if (traitPath) return `${traitPath}.impl`;
10209
+ return undefined;
10210
+ }
10211
+
10212
+ function rustSynVisibility(value) {
10213
+ if (!value) return undefined;
10214
+ if (typeof value === 'string') return value;
10215
+ if (typeof value.kind === 'string') return value.kind;
10216
+ if (typeof value.type === 'string') return value.type;
10217
+ if (value.pub || value.Public) return 'pub';
10218
+ if (value.restricted || value.Restricted) return 'restricted';
10219
+ return undefined;
10220
+ }
10221
+
10222
+ function rustSynLiteralValue(node) {
10223
+ const value = node.value ?? node.lit?.value ?? node.lit;
10224
+ if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return value;
10225
+ return undefined;
10226
+ }
10227
+
10228
+ function rustSynMacroKind(kind) {
10229
+ return /Macro|MacroRules|MacroCall/.test(String(kind));
10230
+ }
10231
+
9760
10232
  function declarationRecord(input, nativeNodeId, name, symbolKind, role = 'definition') {
9761
10233
  return {
9762
10234
  name: String(name),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.26",
3
+ "version": "0.2.27",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",