use std::fmt;
use cairo_lang_debug::DebugWithDb;
use cairo_lang_filesystem::ids::{FileId, SpanInFile};
use cairo_lang_filesystem::span::{TextSpan, TextWidth};
use cairo_lang_proc_macros::HeapSize;
use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
use salsa::Database;
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, HeapSize, salsa::Update)]
pub struct StableLocation<'db> {
stable_ptr: SyntaxStablePtrId<'db>,
inner_span: Option<(TextWidth, TextWidth)>,
}
impl<'db> StableLocation<'db> {
pub fn new(stable_ptr: SyntaxStablePtrId<'db>) -> Self {
Self { stable_ptr, inner_span: None }
}
pub fn with_inner_span(
stable_ptr: SyntaxStablePtrId<'db>,
inner_span: (TextWidth, TextWidth),
) -> Self {
Self { stable_ptr, inner_span: Some(inner_span) }
}
pub fn file_id(&self, db: &'db dyn Database) -> FileId<'db> {
self.stable_ptr.file_id(db)
}
pub fn from_ast<TNode: TypedSyntaxNode<'db>>(db: &'db dyn Database, node: &TNode) -> Self {
Self::new(node.as_syntax_node().stable_ptr(db))
}
pub fn syntax_node(&self, db: &'db dyn Database) -> SyntaxNode<'db> {
self.stable_ptr.lookup(db)
}
pub fn stable_ptr(&self) -> SyntaxStablePtrId<'db> {
self.stable_ptr
}
pub fn span_in_file(&self, db: &'db dyn Database) -> SpanInFile<'db> {
match self.inner_span {
Some((start, width)) => {
let start = self.syntax_node(db).offset(db).add_width(start);
SpanInFile {
file_id: self.file_id(db),
span: TextSpan::new_with_width(start, width),
}
}
None => {
let syntax_node = self.syntax_node(db);
SpanInFile { file_id: self.file_id(db), span: syntax_node.span_without_trivia(db) }
}
}
}
pub fn span_in_file_until(
&self,
db: &'db dyn Database,
until_stable_ptr: SyntaxStablePtrId<'db>,
) -> SpanInFile<'db> {
let start = self.stable_ptr.lookup(db).span_start_without_trivia(db);
let end = until_stable_ptr.lookup(db).span_end_without_trivia(db);
SpanInFile { file_id: self.stable_ptr.file_id(db), span: TextSpan::new(start, end) }
}
}
impl<'db> DebugWithDb<'db> for StableLocation<'db> {
type Db = dyn Database;
fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &'db dyn Database) -> fmt::Result {
let diag_location = self.span_in_file(db);
diag_location.fmt_location(f, db)
}
}