use std::cell::OnceCell;
use std::ops::Deref;
use std::rc::Rc;
use either::Either;
use proc_macro2::Span;
use crate::rust_to_py::py_code_gen::PyMetaModule;
use crate::utils::py_source::PySegment;
#[derive(Debug)]
pub(crate) struct SourceLocation {
pub file: Either<Rc<PyMetaModule>, String>,
pub start_line: usize,
pub start_column: Option<usize>,
pub end_line: Option<usize>,
pub end_column: Option<usize>,
src_span_cache: OnceCell<Option<Span>>,
}
impl SourceLocation {
pub fn new(
file: Either<Rc<PyMetaModule>, String>,
start_line: usize,
start_column: Option<usize>,
end_line: Option<usize>,
end_column: Option<usize>,
) -> Self {
Self {
file,
start_line,
start_column,
end_line,
end_column,
src_span_cache: OnceCell::new(),
}
}
pub fn segments(&self) -> Option<Vec<Rc<PySegment>>> {
if let Either::Left(ref module) = self.file {
let mut segments = Vec::new();
let end_line = self.end_line.unwrap_or(self.start_line);
for lineno in self.start_line..=end_line {
let Some(line) = module.source.lines.get(lineno - 1) else {
break;
};
let mut column = line.indent;
for segment in &line.segments {
let seg_start = column;
column += segment.code.chars().count();
let seg_end = column - 1;
if lineno == self.start_line
&& let Some(start_column) = self.start_column
&& seg_end < start_column
{
continue;
}
if lineno == end_line
&& let Some(end_column) = self.end_column
&& seg_start > end_column
{
continue;
}
segments.push(Rc::clone(segment));
}
}
Some(segments)
} else {
None
}
}
pub fn src_span(&self) -> Option<Span> {
*self.src_span_cache.get_or_init(|| {
if let Either::Left(ref _module) = self.file {
PySegment::join_src_spans(self.segments().unwrap().iter().map(Rc::deref))
} else {
None
}
})
}
}
impl PartialEq for SourceLocation {
fn eq(&self, other: &Self) -> bool {
(match (&self.file, &other.file) {
(Either::Left(ma), Either::Left(mb)) => Rc::ptr_eq(ma, mb),
(Either::Right(fa), Either::Right(fb)) => fa == fb,
_ => false,
}) && self.start_line == other.start_line
&& self.end_line == other.end_line
&& self.start_column == other.start_column
&& self.end_column == other.end_column
}
}
impl Eq for SourceLocation {}
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct FrameSummary {
pub frame_name: String,
pub location: SourceLocation,
}
pub(crate) type StackSummary = Box<[FrameSummary]>;
#[derive(Debug)]
pub(crate) struct PythonError {
pub class: String,
pub msg: String,
pub trace: Option<Either<StackSummary, SourceLocation>>,
}