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

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
@@ -332,6 +332,7 @@ Use injected parser adapters when a real language parser is available but should
332
332
  ```js
333
333
  import {
334
334
  createBabelNativeImporterAdapter,
335
+ createClangAstNativeImporterAdapter,
335
336
  createPythonAstNativeImporterAdapter,
336
337
  createRustSynNativeImporterAdapter,
337
338
  importNativeProject,
@@ -348,6 +349,11 @@ const rustSynAdapter = createRustSynNativeImporterAdapter({
348
349
  parserModule: hostRustSynParser,
349
350
  rustEdition: '2021'
350
351
  });
352
+ const clangAstAdapter = createClangAstNativeImporterAdapter({
353
+ parserModule: hostClangJsonParser,
354
+ cStandard: 'c11',
355
+ compileFlags: ['-std=c11']
356
+ });
351
357
 
352
358
  const imported = await runNativeImporterAdapter(babelAdapter, {
353
359
  sourcePath: 'src/todo.ts',
@@ -356,11 +362,12 @@ const imported = await runNativeImporterAdapter(babelAdapter, {
356
362
 
357
363
  const project = await importNativeProject({
358
364
  projectRoot: 'src',
359
- adapters: [babelAdapter, pythonAstAdapter, rustSynAdapter],
365
+ adapters: [babelAdapter, pythonAstAdapter, rustSynAdapter, clangAstAdapter],
360
366
  sources: [
361
367
  { language: 'typescript', adapter: babelAdapter.id, sourcePath: 'src/todo.ts', sourceText },
362
368
  { language: 'python', adapter: pythonAstAdapter.id, sourcePath: 'tools/todo.py', sourceText: pythonSource },
363
- { language: 'rust', adapter: rustSynAdapter.id, sourcePath: 'src/todo.rs', sourceText: rustSource }
369
+ { language: 'rust', adapter: rustSynAdapter.id, sourcePath: 'src/todo.rs', sourceText: rustSource },
370
+ { language: 'c', adapter: clangAstAdapter.id, sourcePath: 'native/todo.c', sourceText: cSource }
364
371
  ]
365
372
  });
366
373
 
@@ -381,6 +388,7 @@ The built-in adapter factories are dependency-light wrappers for caller-owned pa
381
388
  - `createTypeScriptCompilerNativeImporterAdapter`
382
389
  - `createPythonAstNativeImporterAdapter`
383
390
  - `createRustSynNativeImporterAdapter`
391
+ - `createClangAstNativeImporterAdapter`
384
392
  - `createTreeSitterNativeImporterAdapter`
385
393
 
386
394
  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
@@ -2,6 +2,7 @@ import { performance } from 'node:perf_hooks';
2
2
  import {
3
3
  compileNativeSource,
4
4
  compileFrontierSource,
5
+ createClangAstNativeImporterAdapter,
5
6
  createEstreeNativeImporterAdapter,
6
7
  createNativeImportCoverageMatrix,
7
8
  createNativeParserAstFormatMatrix,
@@ -79,7 +80,7 @@ const matrixDurationMs = performance.now() - matrixStart;
79
80
  const parserFormatMatrixStart = performance.now();
80
81
  const parserFormatMatrix = createNativeParserAstFormatMatrix({
81
82
  imports: nativeImportResults,
82
- adapters: [estreeAdapter, createPythonAstNativeImporterAdapter(), createRustSynNativeImporterAdapter()]
83
+ adapters: [estreeAdapter, createPythonAstNativeImporterAdapter(), createRustSynNativeImporterAdapter(), createClangAstNativeImporterAdapter()]
83
84
  });
84
85
  const parserFormatMatrixDurationMs = performance.now() - parserFormatMatrixStart;
85
86
 
package/dist/index.d.ts CHANGED
@@ -1410,6 +1410,31 @@ export interface RustSynNativeImporterAdapterOptions {
1410
1410
  readonly maxNodes?: number;
1411
1411
  }
1412
1412
 
1413
+ export interface ClangAstNativeImporterAdapterOptions {
1414
+ readonly id?: string;
1415
+ readonly language?: FrontierSourceLanguage;
1416
+ readonly parser?: string;
1417
+ readonly version?: string;
1418
+ readonly capabilities?: readonly string[];
1419
+ readonly coverage?: NativeImporterAdapterCoverageInput;
1420
+ readonly supportedExtensions?: readonly string[];
1421
+ readonly diagnostics?: readonly NativeImporterAdapterDiagnostic[];
1422
+ readonly ast?: unknown;
1423
+ readonly translationUnit?: unknown;
1424
+ readonly tu?: unknown;
1425
+ readonly parse?: (sourceText: string, options: Record<string, unknown>) => unknown;
1426
+ readonly parserModule?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1427
+ readonly clang?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1428
+ readonly libclang?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1429
+ readonly parserOptions?: Record<string, unknown>;
1430
+ readonly cStandard?: 'c89' | 'c99' | 'c11' | 'c17' | 'c23' | 'gnu11' | 'gnu17' | 'gnu23' | string;
1431
+ readonly compileFlags?: readonly string[];
1432
+ readonly includeSystemHeaders?: boolean;
1433
+ readonly preprocessorRecords?: readonly unknown[] | { readonly records?: readonly unknown[] };
1434
+ readonly includeGraph?: unknown;
1435
+ readonly maxNodes?: number;
1436
+ }
1437
+
1413
1438
  export interface TreeSitterNativeImporterAdapterOptions {
1414
1439
  readonly id?: string;
1415
1440
  readonly language?: FrontierSourceLanguage;
@@ -1781,6 +1806,7 @@ export declare function createBabelNativeImporterAdapter(options?: JavaScriptNat
1781
1806
  export declare function createTypeScriptCompilerNativeImporterAdapter(options?: TypeScriptCompilerNativeImporterAdapterOptions): NativeImporterAdapter;
1782
1807
  export declare function createPythonAstNativeImporterAdapter(options?: PythonAstNativeImporterAdapterOptions): NativeImporterAdapter;
1783
1808
  export declare function createRustSynNativeImporterAdapter(options?: RustSynNativeImporterAdapterOptions): NativeImporterAdapter;
1809
+ export declare function createClangAstNativeImporterAdapter(options?: ClangAstNativeImporterAdapterOptions): NativeImporterAdapter;
1784
1810
  export declare function createTreeSitterNativeImporterAdapter(options?: TreeSitterNativeImporterAdapterOptions): NativeImporterAdapter;
1785
1811
  export declare function runNativeImporterAdapter(adapter: NativeImporterAdapter, input: RunNativeImporterAdapterOptions): Promise<NativeImporterAdapterImportResult>;
1786
1812
  export declare function runNativeTargetProjectionAdapter(adapter: NativeTargetProjectionAdapter, input: NativeTargetProjectionAdapterInput): NativeTargetProjectionResult;
package/dist/index.js CHANGED
@@ -403,6 +403,18 @@ export const NativeParserAstFormatProfiles = Object.freeze([
403
403
  supportsErrorRecovery: true,
404
404
  notes: ['rust-analyzer uses rowan-backed concrete syntax trees with AST wrappers; semantic richness still depends on host analysis evidence.']
405
405
  }),
406
+ nativeParserAstFormatProfile('clang-ast-json', {
407
+ aliases: ['clang', 'libclang', 'clang-json', 'clang-ast-dump-json'],
408
+ kind: 'compiler-ast',
409
+ languages: ['c', 'cpp'],
410
+ parserAdapters: ['clang', 'libclang', 'clang-ast-json'],
411
+ exactness: 'exact-parser-ast',
412
+ sourceRangeModel: 'clang-loc-range',
413
+ preservesTokens: false,
414
+ preservesTrivia: false,
415
+ supportsErrorRecovery: false,
416
+ notes: ['Clang JSON AST dumps expose compiler AST declarations and source ranges after preprocessing; compile commands, macros, inactive branches, type checking, and lossless formatting remain host-owned evidence.']
417
+ }),
406
418
  nativeParserAstFormatProfile('tree-sitter', {
407
419
  kind: 'concrete-syntax-tree',
408
420
  languages: ['mixed'],
@@ -2711,6 +2723,64 @@ export function createRustSynNativeImporterAdapter(options = {}) {
2711
2723
  };
2712
2724
  }
2713
2725
 
2726
+ export function createClangAstNativeImporterAdapter(options = {}) {
2727
+ return {
2728
+ id: options.id ?? 'frontier.clang-ast-native-importer',
2729
+ language: options.language ?? 'c',
2730
+ parser: options.parser ?? 'clang',
2731
+ version: options.version,
2732
+ capabilities: uniqueStrings(['nativeAst', 'semanticIndex', 'sourceMaps', 'diagnostics', ...(options.capabilities ?? [])]),
2733
+ coverage: nativeImporterAdapterCoverage({
2734
+ exactness: 'exact-parser-ast',
2735
+ exactAst: true,
2736
+ tokens: false,
2737
+ trivia: false,
2738
+ diagnostics: true,
2739
+ sourceRanges: true,
2740
+ generatedRanges: false,
2741
+ semanticCoverage: declarationSemanticCoverage(),
2742
+ notes: [
2743
+ 'Normalizes caller-owned Clang -ast-dump=json shaped ASTs into native AST nodes and declaration-level semantic index records.',
2744
+ 'Clang JSON ASTs reflect a preprocessed compiler view; compile commands, macros, inactive preprocessor branches, comments/trivia, and full type/reference analysis require host evidence.'
2745
+ ]
2746
+ }, options.coverage),
2747
+ supportedExtensions: options.supportedExtensions ?? ['.c', '.h', '.cc', '.cpp', '.cxx', '.hpp', '.hh'],
2748
+ diagnostics: options.diagnostics,
2749
+ parse(input) {
2750
+ const parsed = input.options?.ast
2751
+ ?? input.options?.nativeAst
2752
+ ?? input.options?.translationUnit
2753
+ ?? input.options?.tu
2754
+ ?? options.ast
2755
+ ?? options.translationUnit
2756
+ ?? options.tu
2757
+ ?? parseClangAstSource(input, options);
2758
+ const root = clangAstRoot(parsed);
2759
+ if (!root) {
2760
+ return missingInjectedParserResult(input, {
2761
+ parser: options.parser ?? 'clang',
2762
+ adapterId: options.id ?? 'frontier.clang-ast-native-importer',
2763
+ message: 'createClangAstNativeImporterAdapter requires an injected Clang JSON AST object, parserModule.parse function, parse function, or adapterOptions.ast.'
2764
+ });
2765
+ }
2766
+ const parseDiagnostics = normalizeParserErrors(parsed?.errors ?? parsed?.diagnostics, input, {
2767
+ parser: options.parser ?? 'clang'
2768
+ });
2769
+ return createNativeImportFromClangAst(root, input, {
2770
+ parser: options.parser ?? 'clang',
2771
+ astFormat: 'clang-ast-json',
2772
+ maxNodes: options.maxNodes,
2773
+ diagnostics: parseDiagnostics,
2774
+ cStandard: options.cStandard ?? input.options?.cStandard ?? parsed?.cStandard,
2775
+ compileFlags: options.compileFlags ?? input.options?.compileFlags ?? parsed?.compileFlags,
2776
+ includeSystemHeaders: options.includeSystemHeaders ?? input.options?.includeSystemHeaders,
2777
+ preprocessorRecords: input.options?.preprocessorRecords ?? options.preprocessorRecords ?? parsed?.preprocessorRecords,
2778
+ includeGraph: input.options?.includeGraph ?? options.includeGraph ?? parsed?.includeGraph
2779
+ });
2780
+ }
2781
+ };
2782
+ }
2783
+
2714
2784
  export function createTreeSitterNativeImporterAdapter(options = {}) {
2715
2785
  return {
2716
2786
  id: options.id ?? `frontier.tree-sitter-${idFragment(options.language ?? 'source')}-native-importer`,
@@ -7151,6 +7221,7 @@ function parserAstFormatIdForParser(parser) {
7151
7221
  if (text.includes('python') && text.includes('ast')) return 'python-ast';
7152
7222
  if (text === 'syn' || text.includes('rust-syn')) return 'rust-syn';
7153
7223
  if (text.includes('rust-analyzer') || text.includes('rowan')) return 'rust-analyzer-rowan';
7224
+ if (text.includes('clang') || text.includes('libclang')) return 'clang-ast-json';
7154
7225
  if (text.includes('tree-sitter') || text.includes('treesitter')) return 'tree-sitter';
7155
7226
  if (text.includes('babel')) return 'babel';
7156
7227
  if (text.includes('estree')) return 'estree';
@@ -8199,6 +8270,23 @@ function parseRustSynSource(input, options) {
8199
8270
  return parse(input.sourceText, parserOptions);
8200
8271
  }
8201
8272
 
8273
+ function parseClangAstSource(input, options) {
8274
+ const parse = options.parse ?? options.parserModule?.parse ?? options.clang?.parse ?? options.libclang?.parse;
8275
+ if (typeof parse !== 'function') return undefined;
8276
+ const parserOptions = {
8277
+ sourcePath: input.sourcePath,
8278
+ filename: input.sourcePath,
8279
+ language: options.language ?? input.language,
8280
+ standard: options.cStandard ?? input.options?.cStandard,
8281
+ compileFlags: options.compileFlags ?? input.options?.compileFlags,
8282
+ includeSystemHeaders: options.includeSystemHeaders ?? input.options?.includeSystemHeaders,
8283
+ astDumpFormat: 'json',
8284
+ ...(options.parserOptions ?? {}),
8285
+ ...(input.options?.parserOptions ?? {})
8286
+ };
8287
+ return parse(input.sourceText, parserOptions);
8288
+ }
8289
+
8202
8290
  function createNativeImportFromSyntaxAst(ast, input, options) {
8203
8291
  const root = normalizeSyntaxAstRoot(ast, options.astFormat);
8204
8292
  if (!root) {
@@ -8319,6 +8407,42 @@ function createNativeImportFromRustSyn(root, input, options) {
8319
8407
  };
8320
8408
  }
8321
8409
 
8410
+ function createNativeImportFromClangAst(root, input, options) {
8411
+ const context = createAstNormalizationContext(input, options);
8412
+ visitClangAstNode(root, context, 'root');
8413
+ for (const [index, record] of clangPreprocessorRecords(options.preprocessorRecords).entries()) {
8414
+ visitClangAstNode(record, context, `preprocessorRecords[${index}]`);
8415
+ }
8416
+ if (context.truncated) {
8417
+ context.losses.push(truncatedAstLoss(input, context, options));
8418
+ }
8419
+ const semantic = semanticIndexFromNativeDeclarations(context.declarations, input, options);
8420
+ return {
8421
+ rootId: context.rootId,
8422
+ nodes: context.nodes,
8423
+ semanticIndex: semantic.semanticIndex,
8424
+ mappings: semantic.mappings,
8425
+ losses: mergeNativeLosses(context.losses, options.diagnostics?.map((diagnostic, index) => adapterDiagnosticToLoss(diagnostic, index, {
8426
+ id: input.adapterId,
8427
+ version: input.adapterVersion
8428
+ }, input)) ?? []),
8429
+ evidence: semantic.evidence,
8430
+ diagnostics: options.diagnostics,
8431
+ metadata: {
8432
+ astFormat: options.astFormat,
8433
+ parser: options.parser,
8434
+ cStandard: options.cStandard,
8435
+ compileFlags: Array.isArray(options.compileFlags) ? options.compileFlags.slice() : options.compileFlags,
8436
+ includeSystemHeaders: Boolean(options.includeSystemHeaders),
8437
+ preprocessorRecordCount: clangPreprocessorRecords(options.preprocessorRecords).length,
8438
+ includeGraph: serializableIncludeGraphSummary(options.includeGraph),
8439
+ normalizedNodeCount: Object.keys(context.nodes).length,
8440
+ declarationCount: context.declarations.length,
8441
+ truncated: context.truncated
8442
+ }
8443
+ };
8444
+ }
8445
+
8322
8446
  function createNativeImportFromTreeSitter(root, input, options) {
8323
8447
  const context = createAstNormalizationContext(input, options);
8324
8448
  visitTreeSitterNode(root, context, 'root');
@@ -8563,6 +8687,67 @@ function visitRustSynNode(node, context, propertyPath) {
8563
8687
  return id;
8564
8688
  }
8565
8689
 
8690
+ function visitClangAstNode(node, context, propertyPath) {
8691
+ if (!isClangAstNode(node) || context.truncated) return undefined;
8692
+ if (context.objectIds.has(node)) return context.objectIds.get(node);
8693
+ if (context.counter >= context.maxNodes) {
8694
+ context.truncated = true;
8695
+ return undefined;
8696
+ }
8697
+ const kind = clangAstKind(node);
8698
+ const span = spanFromClangAstNode(node, context.input);
8699
+ const id = nativeNodeId(context, kind, { start: { line: span?.startLine, column: span?.startColumn } }, propertyPath);
8700
+ context.objectIds.set(node, id);
8701
+ if (!context.rootId) context.rootId = id;
8702
+ const children = [];
8703
+ for (const [field, value] of clangAstChildEntries(node)) {
8704
+ if (Array.isArray(value)) {
8705
+ value.forEach((entry, index) => {
8706
+ const childId = visitClangAstNode(entry, context, `${propertyPath}.${field}[${index}]`);
8707
+ if (childId) children.push(childId);
8708
+ });
8709
+ } else {
8710
+ const childId = visitClangAstNode(value, context, `${propertyPath}.${field}`);
8711
+ if (childId) children.push(childId);
8712
+ }
8713
+ }
8714
+ const declaration = clangAstDeclaration(node, kind, id, context.input);
8715
+ const nativeNode = {
8716
+ id,
8717
+ kind,
8718
+ languageKind: `${context.input.language}.${kind}`,
8719
+ span,
8720
+ value: declaration?.name ?? clangAstNodeValue(node),
8721
+ fields: primitiveClangAstFields(node, kind),
8722
+ children,
8723
+ metadata: {
8724
+ astFormat: context.options.astFormat,
8725
+ propertyPath,
8726
+ clangId: typeof node.id === 'string' || typeof node.id === 'number' ? String(node.id) : undefined,
8727
+ locationKind: clangLocationKind(node)
8728
+ }
8729
+ };
8730
+ context.nodes[id] = nativeNode;
8731
+ if (declaration) context.declarations.push({ ...declaration, nativeNode });
8732
+ if (clangPreprocessorKind(kind)) {
8733
+ context.losses.push({
8734
+ id: `loss_${idFragment(id)}_clang_preprocessor`,
8735
+ severity: 'warning',
8736
+ phase: 'parse',
8737
+ sourceFormat: context.input.language,
8738
+ kind: 'preprocessor',
8739
+ message: 'Clang AST preprocessor records were imported, but macro expansion, inactive branches, and compile-command provenance require host evidence.',
8740
+ span,
8741
+ nodeId: id,
8742
+ metadata: {
8743
+ parser: context.options.parser,
8744
+ astFormat: context.options.astFormat
8745
+ }
8746
+ });
8747
+ }
8748
+ return id;
8749
+ }
8750
+
8566
8751
  function visitTreeSitterNode(node, context, propertyPath) {
8567
8752
  if (!node || typeof node !== 'object' || context.truncated) return undefined;
8568
8753
  if (context.objectIds.has(node)) return context.objectIds.get(node);
@@ -10229,6 +10414,249 @@ function rustSynMacroKind(kind) {
10229
10414
  return /Macro|MacroRules|MacroCall/.test(String(kind));
10230
10415
  }
10231
10416
 
10417
+ function clangAstRoot(value) {
10418
+ if (!value || typeof value !== 'object') return undefined;
10419
+ if (Array.isArray(value)) return { kind: 'TranslationUnitDecl', inner: value };
10420
+ if (isClangAstNode(value)) return value;
10421
+ if (Array.isArray(value.ast)) return { kind: 'TranslationUnitDecl', inner: value.ast };
10422
+ if (isClangAstNode(value.ast)) return value.ast;
10423
+ if (isClangAstNode(value.root)) return value.root;
10424
+ if (isClangAstNode(value.translationUnit)) return value.translationUnit;
10425
+ if (isClangAstNode(value.tu)) return value.tu;
10426
+ if (isClangAstNode(value.file)) return value.file;
10427
+ if (isClangAstNode(value.sourceFile)) return value.sourceFile;
10428
+ return undefined;
10429
+ }
10430
+
10431
+ function isClangAstNode(value) {
10432
+ return Boolean(value && typeof value === 'object' && typeof clangAstKind(value) === 'string');
10433
+ }
10434
+
10435
+ function clangAstKind(node) {
10436
+ if (!node || typeof node !== 'object') return undefined;
10437
+ const declared = node.kind ?? node._type ?? node.type ?? node.nodeType ?? node.declKind ?? node.stmtKind;
10438
+ if (typeof declared === 'string') return declared;
10439
+ if (Array.isArray(node.inner) || Array.isArray(node.children) || Array.isArray(node.decls)) return 'TranslationUnitDecl';
10440
+ return undefined;
10441
+ }
10442
+
10443
+ function ignoredClangAstField(key) {
10444
+ return key === '_type'
10445
+ || key === 'type'
10446
+ || key === 'kind'
10447
+ || key === 'nodeType'
10448
+ || key === 'declKind'
10449
+ || key === 'stmtKind'
10450
+ || key === 'id'
10451
+ || key === 'loc'
10452
+ || key === 'range'
10453
+ || key === 'name'
10454
+ || key === 'displayName'
10455
+ || key === 'qualifiedName'
10456
+ || key === 'mangledName'
10457
+ || key === 'parent'
10458
+ || key === 'parentDeclContextId'
10459
+ || key === 'previousDecl'
10460
+ || key === 'referencedDecl';
10461
+ }
10462
+
10463
+ function primitiveClangAstFields(node, kind) {
10464
+ const fields = { kind };
10465
+ const name = clangDeclarationName(node);
10466
+ if (name) fields.name = name;
10467
+ const type = clangTypeName(node.type ?? node.qualType);
10468
+ if (type) fields.type = type;
10469
+ for (const key of [
10470
+ 'mangledName',
10471
+ 'storageClass',
10472
+ 'tagUsed',
10473
+ 'completeDefinition',
10474
+ 'isThisDeclarationADefinition',
10475
+ 'inline',
10476
+ 'isUsed',
10477
+ 'isReferenced',
10478
+ 'valueCategory',
10479
+ 'opcode',
10480
+ 'castKind'
10481
+ ]) {
10482
+ const value = node[key];
10483
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value === null) fields[key] = value;
10484
+ }
10485
+ const includePath = clangIncludePath(node);
10486
+ if (includePath) fields.includePath = includePath;
10487
+ const literal = clangLiteralValue(node);
10488
+ if (literal !== undefined) fields.literal = literal;
10489
+ const referenced = clangDeclarationName(node.referencedDecl);
10490
+ if (referenced) fields.referenced = referenced;
10491
+ return fields;
10492
+ }
10493
+
10494
+ function spanFromClangAstNode(node, input) {
10495
+ const range = node.range ?? {};
10496
+ const begin = range.begin ?? node.loc ?? node.spellingLoc ?? node.expansionLoc;
10497
+ const end = range.end ?? node.end;
10498
+ const start = clangLocPosition(begin);
10499
+ if (!start) return undefined;
10500
+ const finish = clangLocPosition(end);
10501
+ return {
10502
+ sourceId: input.sourceHash,
10503
+ path: start.path ?? finish?.path ?? input.sourcePath,
10504
+ startLine: start.line,
10505
+ startColumn: start.column,
10506
+ endLine: finish?.line,
10507
+ endColumn: finish?.column
10508
+ };
10509
+ }
10510
+
10511
+ function clangLocPosition(loc) {
10512
+ if (!loc || typeof loc !== 'object') return undefined;
10513
+ const expanded = loc.expansionLoc ?? loc.spellingLoc ?? loc;
10514
+ const line = expanded.line ?? expanded.startLine ?? expanded.begin?.line;
10515
+ const column = expanded.col ?? expanded.column ?? expanded.startColumn ?? expanded.begin?.col ?? expanded.begin?.column;
10516
+ if (typeof line !== 'number') return undefined;
10517
+ return {
10518
+ path: expanded.file ?? expanded.filename ?? expanded.path,
10519
+ line,
10520
+ column: typeof column === 'number' ? column : undefined
10521
+ };
10522
+ }
10523
+
10524
+ function clangLocationKind(node) {
10525
+ const loc = node.loc ?? node.range?.begin;
10526
+ if (!loc || typeof loc !== 'object') return undefined;
10527
+ if (loc.expansionLoc) return 'expansionLoc';
10528
+ if (loc.spellingLoc) return 'spellingLoc';
10529
+ if (loc.includedFrom) return 'includedFrom';
10530
+ return 'clang-loc';
10531
+ }
10532
+
10533
+ function clangAstDeclaration(node, kind, nativeNodeId, input) {
10534
+ if (kind === 'FunctionDecl' || kind === 'CXXMethodDecl' || kind === 'FunctionTemplateDecl') {
10535
+ const name = clangDeclarationName(node);
10536
+ if (name) return declarationRecord(input, nativeNodeId, name, kind === 'CXXMethodDecl' ? 'method' : 'function', clangDeclarationAction(node));
10537
+ }
10538
+ if (kind === 'ParmVarDecl') {
10539
+ const name = clangDeclarationName(node);
10540
+ if (name) return declarationRecord(input, nativeNodeId, name, 'parameter', 'definition');
10541
+ }
10542
+ if (kind === 'RecordDecl' || kind === 'CXXRecordDecl' || kind === 'ClassTemplateDecl') {
10543
+ const name = clangDeclarationName(node);
10544
+ if (name) return declarationRecord(input, nativeNodeId, name, kind === 'CXXRecordDecl' ? 'class' : 'type', clangDeclarationAction(node));
10545
+ }
10546
+ if (kind === 'FieldDecl') {
10547
+ const name = clangDeclarationName(node);
10548
+ if (name) return declarationRecord(input, nativeNodeId, name, 'property', 'definition');
10549
+ }
10550
+ if (kind === 'TypedefDecl' || kind === 'TypeAliasDecl' || kind === 'TypeAliasTemplateDecl') {
10551
+ const name = clangDeclarationName(node);
10552
+ if (name) return declarationRecord(input, nativeNodeId, name, 'type', 'definition');
10553
+ }
10554
+ if (kind === 'EnumDecl') {
10555
+ const name = clangDeclarationName(node);
10556
+ if (name) return declarationRecord(input, nativeNodeId, name, 'type', clangDeclarationAction(node));
10557
+ }
10558
+ if (kind === 'EnumConstantDecl') {
10559
+ const name = clangDeclarationName(node);
10560
+ if (name) return declarationRecord(input, nativeNodeId, name, 'enumMember', 'definition');
10561
+ }
10562
+ if (kind === 'VarDecl') {
10563
+ const name = clangDeclarationName(node);
10564
+ if (name) return declarationRecord(input, nativeNodeId, name, 'variable', clangDeclarationAction(node));
10565
+ }
10566
+ if (/IncludeDirective|InclusionDirective/.test(kind)) {
10567
+ const name = clangIncludePath(node);
10568
+ if (name) return declarationRecord(input, nativeNodeId, name, 'module', 'import');
10569
+ }
10570
+ if (/MacroDefinition|MacroExpansion|MacroInstantiation/.test(kind)) {
10571
+ const name = clangDeclarationName(node) ?? clangIncludePath(node);
10572
+ if (name) return declarationRecord(input, nativeNodeId, name, 'macro', 'definition');
10573
+ }
10574
+ return undefined;
10575
+ }
10576
+
10577
+ function clangDeclarationAction(node) {
10578
+ if (node.isThisDeclarationADefinition === false) return 'declaration';
10579
+ if (node.isThisDeclarationADefinition === true) return 'definition';
10580
+ if (Array.isArray(node.inner) && node.inner.some((entry) => ['CompoundStmt', 'FieldDecl', 'EnumConstantDecl'].includes(clangAstKind(entry)))) return 'definition';
10581
+ return 'declaration';
10582
+ }
10583
+
10584
+ function clangAstChildEntries(node) {
10585
+ const fieldNames = Object.keys(node).filter((key) => !ignoredClangAstField(key));
10586
+ return fieldNames
10587
+ .map((field) => [field, node[field]])
10588
+ .filter(([, value]) => Array.isArray(value)
10589
+ ? value.some(isClangAstNode)
10590
+ : isClangAstNode(value));
10591
+ }
10592
+
10593
+ function clangAstNodeValue(node) {
10594
+ return clangDeclarationName(node)
10595
+ ?? clangIncludePath(node)
10596
+ ?? clangTypeName(node.type ?? node.qualType)
10597
+ ?? clangLiteralValue(node);
10598
+ }
10599
+
10600
+ function clangDeclarationName(node) {
10601
+ if (!node || typeof node !== 'object') return undefined;
10602
+ for (const key of ['qualifiedName', 'displayName', 'name', 'mangledName']) {
10603
+ if (typeof node[key] === 'string' && node[key]) return node[key];
10604
+ }
10605
+ if (node.name && typeof node.name === 'object') return clangDeclarationName(node.name);
10606
+ if (node.referencedDecl && typeof node.referencedDecl === 'object') return clangDeclarationName(node.referencedDecl);
10607
+ if (node.decl && typeof node.decl === 'object') return clangDeclarationName(node.decl);
10608
+ return undefined;
10609
+ }
10610
+
10611
+ function clangIncludePath(node) {
10612
+ if (!node || typeof node !== 'object') return undefined;
10613
+ for (const key of ['file', 'filename', 'path', 'spelling', 'source']) {
10614
+ if (typeof node[key] === 'string' && node[key]) return node[key];
10615
+ }
10616
+ if (node.include && typeof node.include === 'object') return clangIncludePath(node.include);
10617
+ return undefined;
10618
+ }
10619
+
10620
+ function clangTypeName(value) {
10621
+ if (!value) return undefined;
10622
+ if (typeof value === 'string') return value;
10623
+ if (typeof value.qualType === 'string') return value.qualType;
10624
+ if (typeof value.desugaredQualType === 'string') return value.desugaredQualType;
10625
+ if (typeof value.name === 'string') return value.name;
10626
+ if (value.type && typeof value.type === 'object') return clangTypeName(value.type);
10627
+ return undefined;
10628
+ }
10629
+
10630
+ function clangLiteralValue(node) {
10631
+ const value = node.value ?? node.val ?? node.literal;
10632
+ if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return value;
10633
+ if (typeof node.valueAsString === 'string') return node.valueAsString;
10634
+ return undefined;
10635
+ }
10636
+
10637
+ function clangPreprocessorKind(kind) {
10638
+ return /Macro|Preprocess|Preprocessor|IfDirective|IfdefDirective|IfndefDirective|ElifDirective|ElseDirective|EndifDirective/.test(String(kind));
10639
+ }
10640
+
10641
+ function clangPreprocessorRecords(value) {
10642
+ if (!value) return [];
10643
+ if (Array.isArray(value)) return value.filter(isClangAstNode);
10644
+ if (typeof value === 'object' && Array.isArray(value.records)) return value.records.filter(isClangAstNode);
10645
+ if (isClangAstNode(value)) return [value];
10646
+ return [];
10647
+ }
10648
+
10649
+ function serializableIncludeGraphSummary(value) {
10650
+ if (!value || typeof value !== 'object') return undefined;
10651
+ if (Array.isArray(value)) return { edgeCount: value.length };
10652
+ const summary = {};
10653
+ if (typeof value.hash === 'string') summary.hash = value.hash;
10654
+ if (typeof value.root === 'string') summary.root = value.root;
10655
+ if (Array.isArray(value.edges)) summary.edgeCount = value.edges.length;
10656
+ if (Array.isArray(value.includes)) summary.includeCount = value.includes.length;
10657
+ return Object.keys(summary).length ? summary : { present: true };
10658
+ }
10659
+
10232
10660
  function declarationRecord(input, nativeNodeId, name, symbolKind, role = 'definition') {
10233
10661
  return {
10234
10662
  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.27",
3
+ "version": "0.2.28",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",