use anyhow::{Context, Result};
use compiler_base_error::{diagnostic_handler::DiagnosticHandler, Diagnostic, DiagnosticStyle};
use compiler_base_span::{FilePathMapping, SourceMap};
use std::{
path::{Path, PathBuf},
sync::Arc,
};
#[cfg(test)]
mod tests;
pub struct Session {
pub sm: Arc<SourceMap>,
pub diag_handler: Arc<DiagnosticHandler>,
}
impl Session {
#[inline]
pub fn new(sm: Arc<SourceMap>, diag_handler: Arc<DiagnosticHandler>) -> Self {
Self { sm, diag_handler }
}
pub fn new_with_file_and_code(filename: &str, code: Option<&str>) -> Result<Self> {
let sm = SourceMap::new(FilePathMapping::empty());
match code {
Some(c) => {
sm.new_source_file(PathBuf::from(filename).into(), c.to_string());
}
None => {
sm.load_file(&Path::new(&filename))
.with_context(|| "Failed to load source file")?;
}
}
let diag = DiagnosticHandler::default();
Ok(Self {
sm: Arc::new(sm),
diag_handler: Arc::new(diag),
})
}
#[inline]
pub fn new_with_src_code(code: &str) -> Result<Self> {
let sm = SourceMap::new(FilePathMapping::empty());
sm.new_source_file(PathBuf::from("").into(), code.to_string());
let diag = DiagnosticHandler::default();
Ok(Self {
sm: Arc::new(sm),
diag_handler: Arc::new(diag),
})
}
#[inline]
pub fn emit_stashed_diagnostics_and_abort(&self) -> Result<&Self> {
self.diag_handler
.abort_if_errors()
.with_context(|| "Internal Bug: Fail to display error diagnostic")?;
Ok(self)
}
#[inline]
pub fn emit_all_diags_into_string(&self) -> Result<Vec<Result<String>>> {
self.diag_handler.emit_all_diags_into_string()
}
#[inline]
pub fn emit_nth_diag_into_string(&self, index: usize) -> Result<Option<Result<String>>> {
self.diag_handler.emit_nth_diag_into_string(index)
}
pub fn emit_stashed_diagnostics(&self) -> Result<&Self> {
self.diag_handler
.emit_stashed_diagnostics()
.with_context(|| "Internal Bug: Fail to display error diagnostic")?;
Ok(self)
}
pub fn add_err(&self, err: impl SessionDiagnostic) -> Result<&Self> {
self.diag_handler
.add_err_diagnostic(err.into_diagnostic(self)?)?;
Ok(self)
}
pub fn add_warn(&self, warn: impl SessionDiagnostic) -> Result<&Self> {
self.diag_handler
.add_warn_diagnostic(warn.into_diagnostic(self)?)?;
Ok(self)
}
#[inline]
pub fn diagnostics_count(&self) -> Result<usize> {
self.diag_handler.diagnostics_count()
}
}
impl Default for Session {
fn default() -> Self {
Self {
sm: Arc::new(SourceMap::new(FilePathMapping::empty())),
diag_handler: Arc::new(DiagnosticHandler::default()),
}
}
}
pub trait SessionDiagnostic {
fn into_diagnostic(self, sess: &Session) -> Result<Diagnostic<DiagnosticStyle>>;
}