tvl-depot/tvix/eval/src/source.rs
Vincent Ambo 1e2d323a7c feat(tvix/eval): fancy-format parse errors returned by rnix
This change is quite verbose, so a little bit of explaining:

1. To correctly format parse errors, errors must be able to return
   more than one annotated span (the parser returns a list of errors
   for each span).

   To accomplish this, the structure of how the `Diagnostic` struct
   which formats an error is constructed has changed to delegate the
   creation of the `SpanLabel` vector to the kind of error.

2. The rnix structures don't have human-readable output formats by
   default, so some verbose methods for formatting them in
   human-readable ways have been added in the errors module. We might
   want to move these out into a submodule.

3. In many cases, the errors returned by rnix are a bit strange - so
   while we format them with all information that is easily available
   they may look weird or not necessarily help users. Consider this CL
   only a first step in the right direction.

Change-Id: Ie7dd74751af9e7ecb35d751f8b087aae5ae6e2e8
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6871
Reviewed-by: sterni <sternenseemann@systemli.org>
Autosubmit: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
2022-10-08 17:27:57 +00:00

63 lines
2 KiB
Rust

//! This module contains utilities for dealing with the codemap that
//! needs to be carried across different compiler instantiations in an
//! evaluation.
//!
//! The data type `SourceCode` should be carried through all relevant
//! places instead of copying the codemap structures directly.
use std::{
cell::{Ref, RefCell, RefMut},
rc::Rc,
sync::Arc,
};
use codemap::{CodeMap, Span};
/// Tracks all source code in a Tvix evaluation for accurate error
/// reporting.
#[derive(Clone)]
pub struct SourceCode(Rc<RefCell<CodeMap>>);
impl SourceCode {
/// Create a new SourceCode instance.
pub fn new() -> Self {
SourceCode(Rc::new(RefCell::new(CodeMap::new())))
}
/// Access a read-only reference to the codemap.
pub fn codemap(&self) -> Ref<CodeMap> {
self.0.borrow()
}
/// Access a writable reference to the codemap.
fn codemap_mut(&self) -> RefMut<CodeMap> {
self.0.borrow_mut()
}
/// Add a file to the codemap. The returned Arc is managed by the
/// codemap internally and can be used like a normal reference.
pub fn add_file(&self, name: String, code: String) -> Arc<codemap::File> {
self.codemap_mut().add_file(name, code)
}
/// Retrieve the line number of the given span. If it spans
/// multiple lines, the first line will be returned.
pub fn get_line(&self, span: Span) -> usize {
// lines are 0-indexed in the codemap, but users probably want
// real line numbers
self.codemap().look_up_span(span).begin.line + 1
}
/// Returns the literal source slice of the given span.
pub fn source_slice(&self, span: Span) -> Ref<str> {
Ref::map(self.codemap(), |c| {
c.find_file(span.low()).source_slice(span)
})
}
/// Returns the reference to the file structure that a given span
/// is in.
pub fn get_file(&self, span: Span) -> Arc<codemap::File> {
self.codemap().look_up_span(span).file
}
}