mod build_model;
mod diagnostics;
mod syntax;
mod validate;
use self::{build_model::build_file, diagnostics::collect_diagnostics, validate::validate_file};
use super::{
Diagnostic,
model::{AchitekFile, ValidAchitekFile},
parser::{self, ParseError},
};
use std::{
backtrace::Backtrace,
error::Error as StdError,
fmt::{Display, Formatter},
};
#[derive(Debug, Clone)]
pub struct Analysis<'a> {
source: &'a str,
file: AchitekFile,
diagnostics: Vec<Diagnostic>,
}
impl<'a> Analysis<'a> {
pub fn source(&self) -> &'a str {
self.source
}
pub fn file(&self) -> &AchitekFile {
&self.file
}
pub fn diagnostics(&self) -> &[Diagnostic] {
&self.diagnostics
}
pub fn has_errors(&self) -> bool {
self.diagnostics
.iter()
.any(|diagnostic| diagnostic.severity() == super::Severity::Error)
}
pub fn into_valid(self) -> Result<ValidAchitekFile, Vec<Diagnostic>> {
if self.has_errors() {
return Err(self.diagnostics);
}
Ok(validate_file(self.file))
}
}
#[derive(Debug)]
pub struct AnalysisError {
kind: AnalysisErrorKind,
backtrace: Backtrace,
}
impl AnalysisError {
pub fn is_parse(&self) -> bool {
matches!(self.kind, AnalysisErrorKind::Parse(_))
}
pub fn parse_error(&self) -> Option<&ParseError> {
match &self.kind {
AnalysisErrorKind::Parse(source) => Some(source),
}
}
pub fn backtrace(&self) -> &Backtrace {
&self.backtrace
}
}
impl From<ParseError> for AnalysisError {
fn from(source: ParseError) -> Self {
Self {
kind: AnalysisErrorKind::Parse(source),
backtrace: Backtrace::capture(),
}
}
}
impl Display for AnalysisError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.kind {
AnalysisErrorKind::Parse(source) => {
writeln!(f, "failed to parse achitekfile source: {source}")?;
}
}
write!(f, "backtrace:\n{}", self.backtrace)
}
}
impl StdError for AnalysisError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match &self.kind {
AnalysisErrorKind::Parse(source) => Some(source),
}
}
}
#[derive(Debug)]
enum AnalysisErrorKind {
Parse(ParseError),
}
pub fn analyze(source: &str) -> Result<Analysis<'_>, AnalysisError> {
let tree = parser::parse_tree(source)?;
let file = build_file(&tree, source);
let diagnostics = collect_diagnostics(&tree, source, &file);
Ok(Analysis {
source,
file,
diagnostics,
})
}