runmat-hir 0.4.8

High-level IR for RunMat with type inference and lowering utilities
Documentation
use crate::Span;
use std::sync::{OnceLock, RwLock};

const DEFAULT_ERROR_NAMESPACE: &str = "RunMat";
static ERROR_NAMESPACE: OnceLock<RwLock<String>> = OnceLock::new();

fn error_namespace_store() -> &'static RwLock<String> {
    ERROR_NAMESPACE.get_or_init(|| RwLock::new(DEFAULT_ERROR_NAMESPACE.to_string()))
}

pub fn set_error_namespace(namespace: &str) {
    let namespace = if namespace.trim().is_empty() {
        DEFAULT_ERROR_NAMESPACE.to_string()
    } else {
        namespace.to_string()
    };
    if let Ok(mut guard) = error_namespace_store().write() {
        *guard = namespace;
    }
}

pub(crate) fn error_namespace() -> String {
    error_namespace_store()
        .read()
        .map(|guard| guard.clone())
        .unwrap_or_else(|_| DEFAULT_ERROR_NAMESPACE.to_string())
}

#[derive(Debug, Clone)]
pub struct SemanticError {
    pub message: String,
    pub span: Option<Span>,
    pub identifier: Option<String>,
}

impl SemanticError {
    pub fn new(message: impl Into<String>) -> Self {
        Self {
            message: message.into(),
            span: None,
            identifier: None,
        }
    }

    pub fn with_span(mut self, span: Span) -> Self {
        self.span = Some(span);
        self
    }

    pub fn with_identifier(mut self, identifier: impl Into<String>) -> Self {
        self.identifier = Some(identifier.into());
        self
    }
}

impl std::fmt::Display for SemanticError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.message)
    }
}

impl std::error::Error for SemanticError {}

impl From<String> for SemanticError {
    fn from(value: String) -> Self {
        SemanticError::new(value)
    }
}