knave 0.12.6

A Lisp programming language for humans and agents that infers types and ownership and compiles to readable Rust
Documentation
use std::ops::Range;

use super::fragment::Fragment;
use crate::source::Span;

#[derive(Default)]
pub struct SpanMap {
    entries: Vec<(Range<usize>, Span)>,
}

impl SpanMap {
    pub fn source_of(&self, rust: Range<usize>) -> Option<Span> {
        self.entries
            .iter()
            .filter(|(range, _)| range.start <= rust.start && rust.end <= range.end)
            .min_by_key(|(range, _)| range.end - range.start)
            .map(|(_, span)| *span)
    }

    pub fn moved(&self, boundaries: &[usize]) -> Self {
        let entries = self
            .entries
            .iter()
            .filter_map(|(range, span)| {
                let start = *boundaries.get(range.start)?;
                let end = *boundaries.get(range.end)?;
                (start <= end).then_some((start..end, *span))
            })
            .collect();
        Self { entries }
    }
}

#[derive(Default)]
pub struct RustWriter {
    output: String,
    indentation: usize,
    at_line_start: bool,
    span_map: SpanMap,
}

impl RustWriter {
    const INDENT: &str = "    ";

    pub fn write(&mut self, fragments: &[Fragment]) {
        for fragment in fragments {
            match fragment {
                Fragment::Text(text) => self.text(text),
                Fragment::Newline => self.newline(),
                Fragment::Indented(inner) => self.indented(inner),
                Fragment::Spanned(span, inner) => self.spanned(*span, inner),
            }
        }
    }

    pub fn finish(self) -> (String, SpanMap) {
        (self.output, self.span_map)
    }

    fn text(&mut self, text: &str) {
        if self.at_line_start {
            self.output.push_str(&Self::INDENT.repeat(self.indentation));
            self.at_line_start = false;
        }
        self.output.push_str(text);
    }

    fn newline(&mut self) {
        self.output.push('\n');
        self.at_line_start = true;
    }

    fn indented(&mut self, inner: &[Fragment]) {
        self.indentation += 1;
        self.write(inner);
        self.indentation -= 1;
    }

    fn spanned(&mut self, span: Span, inner: &[Fragment]) {
        let start = self.output.len();
        self.write(inner);
        self.span_map.entries.push((start..self.output.len(), span));
    }
}