use crate::lower::ir;
use microcad_lang_base::{
ComputedHash, Hashed, Identifier, LineCol, ResourceLocation, SourceLocInfo, SrcRef,
SrcReferrer, Url,
};
#[derive(Clone, Debug)]
pub struct Source {
pub doc: Option<ir::DocBlock>,
pub name: ir::QualifiedName,
pub statements: ir::StatementList,
pub url: Url,
pub source: Hashed<String>,
pub line_offset: u32,
}
impl Source {
pub fn new(
doc: Option<ir::DocBlock>,
statements: ir::StatementList,
source: Hashed<String>,
url: Url,
) -> Self {
Self {
doc,
statements,
source,
url,
name: ir::QualifiedName::default(),
line_offset: 0,
}
}
pub fn with_line_offset(self, line_offset: u32) -> Self {
let mut src = self;
src.line_offset = line_offset;
src
}
pub fn id(&self) -> Identifier {
self.name.last().unwrap_or(&Identifier::none()).clone()
}
pub fn filename(&self) -> std::path::PathBuf {
self.to_file_path()
.unwrap_or(std::path::PathBuf::from("<NO FILE>"))
}
pub fn set_filename(&mut self, path: impl AsRef<std::path::Path>) {
assert!(self.to_file_path().is_none());
self.url = Url::from_file_path(
path.as_ref()
.canonicalize()
.unwrap_or(path.as_ref().to_path_buf()),
)
.unwrap_or(self.url.clone());
}
pub fn get_code(&self, src_ref: &SrcRef) -> &str {
let range = &src_ref.range;
&self.source[range.start..range.end]
}
pub fn set_name(&mut self, name: ir::QualifiedName) {
self.name = name
}
pub fn source_loc_info<'a>(&'a self) -> SourceLocInfo<'a> {
SourceLocInfo {
code: &self.source,
url: self.url.clone(),
line_offset: self.line_offset,
}
}
}
impl ResourceLocation for Source {
fn url(&self) -> µcad_lang_base::Url {
&self.url
}
}
impl std::fmt::Display for Source {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.statements.iter().try_for_each(|s| writeln!(f, "{s}"))
}
}
impl SrcReferrer for Source {
fn src_ref(&self) -> SrcRef {
SrcRef::new(
0..self.source.len(),
LineCol::default(),
self.source.computed_hash(),
)
}
}