clean up
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use miette::{Diagnostic, NamedSource, SourceSpan};
|
||||
use thiserror::Error;
|
||||
|
||||
pub type Result<T> = core::result::Result<T, Box<Error>>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum SourceType {
|
||||
/// dir
|
||||
Eval(Arc<PathBuf>),
|
||||
/// dir
|
||||
Repl(Arc<PathBuf>),
|
||||
/// file
|
||||
File(Arc<PathBuf>),
|
||||
/// virtual (name, no path)
|
||||
Virtual(Arc<str>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Source {
|
||||
pub ty: SourceType,
|
||||
pub src: Arc<str>,
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Source {
|
||||
type Error = Box<Error>;
|
||||
fn try_from(value: &str) -> Result<Self> {
|
||||
Source::new_eval(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Source> for NamedSource<Arc<str>> {
|
||||
fn from(value: Source) -> Self {
|
||||
let name = value.get_name();
|
||||
NamedSource::new(name, value.src.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Source {
|
||||
pub fn new_file(path: PathBuf) -> std::io::Result<Self> {
|
||||
Ok(Source {
|
||||
src: std::fs::read_to_string(&path)?.into(),
|
||||
ty: crate::error::SourceType::File(Arc::new(path)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_eval(src: String) -> Result<Self> {
|
||||
Ok(Self {
|
||||
ty: std::env::current_dir()
|
||||
.map_err(|err| Error::internal(format!("Failed to get current working dir: {err}")))
|
||||
.map(Arc::new)
|
||||
.map(SourceType::Eval)?,
|
||||
src: src.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_repl(src: String) -> Result<Self> {
|
||||
Ok(Self {
|
||||
ty: std::env::current_dir()
|
||||
.map_err(|err| Error::internal(format!("Failed to get current working dir: {err}")))
|
||||
.map(Arc::new)
|
||||
.map(SourceType::Repl)?,
|
||||
src: src.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_virtual(name: Arc<str>, src: String) -> Self {
|
||||
Self {
|
||||
ty: SourceType::Virtual(name),
|
||||
src: src.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dir(&self) -> &Path {
|
||||
use SourceType::*;
|
||||
match &self.ty {
|
||||
Eval(dir) | Repl(dir) => dir.as_ref(),
|
||||
File(file) => file
|
||||
.as_path()
|
||||
.parent()
|
||||
.expect("source file must have a parent dir"),
|
||||
Virtual(_) => Path::new("/"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> String {
|
||||
match &self.ty {
|
||||
SourceType::Eval(_) => "«eval»".into(),
|
||||
SourceType::Repl(_) => "«repl»".into(),
|
||||
SourceType::File(path) => path.as_os_str().to_string_lossy().to_string(),
|
||||
SourceType::Virtual(name) => name.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Diagnostic)]
|
||||
pub enum Error {
|
||||
#[error("Parse error: {message}")]
|
||||
#[diagnostic(code(nix::parse))]
|
||||
ParseError {
|
||||
#[source_code]
|
||||
src: Option<NamedSource<Arc<str>>>,
|
||||
#[label("error occurred here")]
|
||||
span: Option<SourceSpan>,
|
||||
message: String,
|
||||
},
|
||||
|
||||
#[error("Downgrade error: {message}")]
|
||||
#[diagnostic(code(nix::downgrade))]
|
||||
DowngradeError {
|
||||
#[source_code]
|
||||
src: Option<NamedSource<Arc<str>>>,
|
||||
#[label("{message}")]
|
||||
span: Option<SourceSpan>,
|
||||
message: String,
|
||||
},
|
||||
|
||||
#[error("Evaluation error: {message}")]
|
||||
#[diagnostic(code(nix::eval))]
|
||||
EvalError {
|
||||
#[source_code]
|
||||
src: Option<NamedSource<Arc<str>>>,
|
||||
#[label("error occurred here")]
|
||||
span: Option<SourceSpan>,
|
||||
message: String,
|
||||
#[help]
|
||||
js_backtrace: Option<String>,
|
||||
#[related]
|
||||
stack_trace: Vec<StackFrame>,
|
||||
},
|
||||
|
||||
#[error("Internal error: {message}")]
|
||||
#[diagnostic(code(nix::internal))]
|
||||
InternalError { message: String },
|
||||
|
||||
#[error("{message}")]
|
||||
#[diagnostic(code(nix::catchable))]
|
||||
Catchable { message: String },
|
||||
|
||||
#[error("Unknown error")]
|
||||
#[diagnostic(code(nix::unknown))]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn parse_error(msg: String) -> Box<Self> {
|
||||
Error::ParseError {
|
||||
src: None,
|
||||
span: None,
|
||||
message: msg,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn downgrade_error(msg: String, src: Source, span: rnix::TextRange) -> Box<Self> {
|
||||
Error::DowngradeError {
|
||||
src: Some(src.into()),
|
||||
span: Some(text_range_to_source_span(span)),
|
||||
message: msg,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn eval_error(msg: String, backtrace: Option<String>) -> Box<Self> {
|
||||
Error::EvalError {
|
||||
src: None,
|
||||
span: None,
|
||||
message: msg,
|
||||
js_backtrace: backtrace,
|
||||
stack_trace: Vec::new(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn internal(msg: String) -> Box<Self> {
|
||||
Error::InternalError { message: msg }.into()
|
||||
}
|
||||
|
||||
pub fn catchable(msg: String) -> Box<Self> {
|
||||
Error::Catchable { message: msg }.into()
|
||||
}
|
||||
|
||||
pub fn with_span(mut self: Box<Self>, span: rnix::TextRange) -> Box<Self> {
|
||||
use Error::*;
|
||||
let source_span = Some(text_range_to_source_span(span));
|
||||
let (ParseError { span, .. } | DowngradeError { span, .. } | EvalError { span, .. }) =
|
||||
self.as_mut()
|
||||
else {
|
||||
return self;
|
||||
};
|
||||
*span = source_span;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_source(mut self: Box<Self>, source: Source) -> Box<Self> {
|
||||
use Error::*;
|
||||
let new_src = Some(source.into());
|
||||
let (ParseError { src, .. } | DowngradeError { src, .. } | EvalError { src, .. }) =
|
||||
self.as_mut()
|
||||
else {
|
||||
return self;
|
||||
};
|
||||
*src = new_src;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_range_to_source_span(range: rnix::TextRange) -> SourceSpan {
|
||||
let start = usize::from(range.start());
|
||||
let len = usize::from(range.end()) - start;
|
||||
SourceSpan::new(start.into(), len)
|
||||
}
|
||||
|
||||
/// Stack frame types from Nix evaluation
|
||||
#[derive(Debug, Clone, Error, Diagnostic)]
|
||||
#[error("{message}")]
|
||||
pub struct StackFrame {
|
||||
#[label]
|
||||
pub span: SourceSpan,
|
||||
#[help]
|
||||
pub message: String,
|
||||
#[source_code]
|
||||
pub src: NamedSource<Arc<str>>,
|
||||
}
|
||||
Reference in New Issue
Block a user