@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 +9 -2
- package/bench/smoke.mjs +2 -1
- package/dist/index.d.ts +23 -0
- package/dist/index.js +472 -0
- package/package.json +1 -1
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