feat: stack var (WIP)
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
//! handling here, we ensure a consistent approach to reporting failures across
|
||||
//! different stages of processing, from parsing to final evaluation.
|
||||
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
|
||||
/// A specialized `Result` type used for all fallible operations within the
|
||||
@@ -12,7 +13,7 @@ pub type Result<T> = core::result::Result<T, Error>;
|
||||
/// The primary error enum, encompassing all potential failures that can occur
|
||||
/// during the lifecycle of a Nix expression's evaluation.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
pub enum ErrorKind {
|
||||
/// An error occurred during the initial parsing phase. This typically
|
||||
/// indicates a syntax error in the Nix source code, as detected by the
|
||||
/// `rnix` parser.
|
||||
@@ -47,3 +48,112 @@ pub enum Error {
|
||||
#[error("an unknown or unexpected error occurred")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
pub kind: ErrorKind,
|
||||
pub span: Option<rnix::TextRange>,
|
||||
pub source: Option<Rc<str>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Basic display
|
||||
write!(f, "{}", self.kind)?;
|
||||
|
||||
// If we have source and span, print context
|
||||
if let (Some(source), Some(span)) = (&self.source, self.span) {
|
||||
let start_byte = usize::from(span.start());
|
||||
let end_byte = usize::from(span.end());
|
||||
|
||||
if start_byte > source.len() || end_byte > source.len() {
|
||||
return Ok(()); // Span is out of bounds
|
||||
}
|
||||
|
||||
let mut start_line = 1;
|
||||
let mut start_col = 1usize;
|
||||
let mut line_start_byte = 0;
|
||||
for (i, c) in source.char_indices() {
|
||||
if i >= start_byte {
|
||||
break;
|
||||
}
|
||||
if c == '\n' {
|
||||
start_line += 1;
|
||||
start_col = 1;
|
||||
line_start_byte = i + 1;
|
||||
} else {
|
||||
start_col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let line_end_byte = source[line_start_byte..]
|
||||
.find('\n')
|
||||
.map(|i| line_start_byte + i)
|
||||
.unwrap_or(source.len());
|
||||
|
||||
let line_str = &source[line_start_byte..line_end_byte];
|
||||
|
||||
let underline_len = if end_byte > start_byte {
|
||||
end_byte - start_byte
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
write!(f, "\n --> {}:{}", start_line, start_col)?;
|
||||
write!(f, "\n |\n")?;
|
||||
write!(f, "{:4} | {}\n", start_line, line_str)?;
|
||||
write!(
|
||||
f,
|
||||
" | {}{}",
|
||||
" ".repeat(start_col.saturating_sub(1)),
|
||||
"^".repeat(underline_len)
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
Some(&self.kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new(kind: ErrorKind) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
span: None,
|
||||
source: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_span(mut self, span: rnix::TextRange) -> Self {
|
||||
self.span = Some(span);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_source(mut self, source: Rc<str>) -> Self {
|
||||
self.source = Some(source);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn parse_error(msg: String) -> Self {
|
||||
Self::new(ErrorKind::ParseError(msg))
|
||||
}
|
||||
pub fn downgrade_error(msg: String) -> Self {
|
||||
Self::new(ErrorKind::DowngradeError(msg))
|
||||
}
|
||||
pub fn resolution_error(msg: String) -> Self {
|
||||
Self::new(ErrorKind::ResolutionError(msg))
|
||||
}
|
||||
pub fn eval_error(msg: String) -> Self {
|
||||
Self::new(ErrorKind::EvalError(msg))
|
||||
}
|
||||
pub fn catchable(msg: String) -> Self {
|
||||
Self::new(ErrorKind::Catchable(msg))
|
||||
}
|
||||
pub fn unknown() -> Self {
|
||||
Self::new(ErrorKind::Unknown)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user