Module patch_applicator

Module patch_applicator 

Source
Expand description

Patch application with source mapping.

§Patch Application Engine

This module provides the core patch application functionality that transforms source code according to patches generated by macros. It supports multiple patch types and generates bidirectional source mappings for IDE integration.

§Patch Types

The engine supports five patch operations:

TypeDescription
InsertInsert formatted AST node at position
InsertRawInsert raw text at position
ReplaceReplace span with formatted AST node
ReplaceRawReplace span with raw text
DeleteRemove span entirely

§Application Strategy

Patches are sorted by position and applied in forward order, with the source mapping tracking position shifts:

Original:  "class Foo {}"
                     ^ Insert " bar: string;" at position 11

Expanded:  "class Foo { bar: string;}"

Source Mapping:
  Segment 1: original[0-11] -> expanded[0-11]  (unchanged: "class Foo {")
  Generated: expanded[11-25] = " bar: string;" (from macro "Test")
  Segment 2: original[11-12] -> expanded[25-26] (unchanged: "}")

§Source Mapping

The engine generates source mapping data that enables:

  • Converting positions from original to expanded code
  • Converting positions from expanded back to original
  • Identifying which macro generated specific code regions
  • Mapping IDE diagnostics to original source locations

§Example Usage

use macroforge_ts::host::patch_applicator::{PatchApplicator, PatchCollector};
use macroforge_ts::host::Result;
use macroforge_ts::ts_syn::abi::{Patch, SpanIR};

fn example() -> Result<()> {
    let source = "class Foo {}";

    // Using PatchApplicator directly
    let patch = Patch::Insert {
        at: SpanIR { start: 12, end: 12 },  // 1-based position
        code: " bar: string;".into(),
        source_macro: Some("Test".to_string()),
    };

    let applicator = PatchApplicator::new(source, vec![patch]);
    let result = applicator.apply_with_mapping(None)?;

    assert_eq!(result.code, "class Foo { bar: string;}");
    assert!(!result.mapping.is_empty());

    // Using PatchCollector for multiple macros
    let mut collector = PatchCollector::new();

    // Add patches from different macros
    let debug_patch = Patch::Insert {
        at: SpanIR { start: 12, end: 12 },
        code: " toString() { return 'Foo'; }".into(),
        source_macro: Some("Debug".to_string()),
    };
    collector.add_runtime_patches(vec![debug_patch]);

    // Apply all collected patches
    let runtime_result = collector.apply_runtime_patches_with_mapping(source, None)?;
    Ok(())
}

Structs§

ApplyResult
Result of applying patches with source mapping
PatchApplicator
Applies patches to source code
PatchCollector
Builder for collecting and applying patches from multiple macros