API Stability Notice

Macroforge is under active development. The API is not yet stable and may change between versions. Some documentation sections may be outdated.

PositionMapper

Maps positions between original source code and macro-expanded code. Essential for accurate error reporting and debugging.

Getting a Mapper

TypeScript
import { NativePlugin, PositionMapper } from "macroforge";

const plugin = new NativePlugin();
const result = plugin.processFile("user.ts", code, { version: "1" });

// Get the mapper for this file
const mapper = plugin.getMapper("user.ts");
if (mapper) {
  // Use the mapper...
}

Methods

isEmpty()

Check if the mapper has any mappings:

TypeScript
isEmpty(): boolean

originalToExpanded()

Map a position from original to expanded code:

TypeScript
originalToExpanded(pos: number): number

expandedToOriginal()

Map a position from expanded to original code:

TypeScript
expandedToOriginal(pos: number): number | null

Returns null if the position is in generated code.

isInGenerated()

Check if a position is in macro-generated code:

TypeScript
isInGenerated(pos: number): boolean

generatedBy()

Get the name of the macro that generated code at a position:

TypeScript
generatedBy(pos: number): string | null

mapSpanToOriginal()

Map a span (range) from expanded to original code:

TypeScript
mapSpanToOriginal(start: number, length: number): SpanResult | null

interface SpanResult {
  start: number;
  length: number;
}

mapSpanToExpanded()

Map a span from original to expanded code:

TypeScript
mapSpanToExpanded(start: number, length: number): SpanResult

Example: Error Position Mapping

TypeScript
import { NativePlugin } from "macroforge";

const plugin = new NativePlugin();

function mapError(filepath: string, expandedPos: number, message: string) {
  const mapper = plugin.getMapper(filepath);
  if (!mapper) return null;

  // Check if the error is in generated code
  if (mapper.isInGenerated(expandedPos)) {
    const macroName = mapper.generatedBy(expandedPos);
    return {
      message: `Error in code generated by @derive(${macroName}): ${message}`,
      // Find the @derive decorator position
      position: findDecoratorPosition(filepath)
    };
  }

  // Map to original position
  const originalPos = mapper.expandedToOriginal(expandedPos);
  if (originalPos !== null) {
    return {
      message,
      position: originalPos
    };
  }

  return null;
}

Performance

Position mapping uses binary search with O(log n) complexity:

  • Fast lookups even for large files
  • Minimal memory overhead
  • Thread-safe access