about summary refs log tree commit diff
path: root/tvix/eval/src/compiler/spans.rs
//! Utilities for dealing with span tracking in the compiler.

use super::*;
use codemap::{File, Span};
use rowan::ast::AstNode;

/// Trait implemented by all types from which we can retrieve a span.
pub(super) trait ToSpan {
    fn span_for(&self, file: &File) -> Span;
}

impl ToSpan for Span {
    fn span_for(&self, _: &File) -> Span {
        *self
    }
}

impl ToSpan for rnix::SyntaxToken {
    fn span_for(&self, file: &File) -> Span {
        let rowan_span = self.text_range();
        file.span.subspan(
            u32::from(rowan_span.start()) as u64,
            u32::from(rowan_span.end()) as u64,
        )
    }
}

impl ToSpan for rnix::SyntaxNode {
    fn span_for(&self, file: &File) -> Span {
        let rowan_span = self.text_range();
        file.span.subspan(
            u32::from(rowan_span.start()) as u64,
            u32::from(rowan_span.end()) as u64,
        )
    }
}

/// Generates a `ToSpan` implementation for a type implementing
/// `rowan::AstNode`. This is impossible to do as a blanket
/// implementation because `rustc` forbids these implementations for
/// traits from third-party crates due to a belief that semantic
/// versioning truly could work (it doesn't).
macro_rules! expr_to_span {
    ( $type:path ) => {
        impl ToSpan for $type {
            fn span_for(&self, file: &File) -> Span {
                self.syntax().span_for(file)
            }
        }
    };
}

expr_to_span!(ast::Expr);
expr_to_span!(ast::Apply);
expr_to_span!(ast::Assert);
expr_to_span!(ast::Attr);
expr_to_span!(ast::AttrSet);
expr_to_span!(ast::Attrpath);
expr_to_span!(ast::AttrpathValue);
expr_to_span!(ast::BinOp);
expr_to_span!(ast::HasAttr);
expr_to_span!(ast::Ident);
expr_to_span!(ast::IdentParam);
expr_to_span!(ast::IfElse);
expr_to_span!(ast::Inherit);
expr_to_span!(ast::Interpol);
expr_to_span!(ast::Lambda);
expr_to_span!(ast::LegacyLet);
expr_to_span!(ast::LetIn);
expr_to_span!(ast::List);
expr_to_span!(ast::Literal);
expr_to_span!(ast::PatBind);
expr_to_span!(ast::Path);
expr_to_span!(ast::Pattern);
expr_to_span!(ast::Select);
expr_to_span!(ast::Str);
expr_to_span!(ast::UnaryOp);
expr_to_span!(ast::With);

impl Compiler<'_> {
    pub(super) fn span_for<S: ToSpan>(&self, to_span: &S) -> Span {
        to_span.span_for(&self.file)
    }
}