use scc::HashMap as SccHashMap;
use crate::report::{ErrorKey, warn};
use crate::scopes::Scopes;
use crate::token::Token;
#[derive(Debug)]
pub struct VariableScopes {
namespace: &'static str,
scopes: SccHashMap<&'static str, (Scopes, bool)>,
}
impl VariableScopes {
pub fn new(namespace: &'static str) -> Self {
Self { namespace, scopes: SccHashMap::default() }
}
#[allow(dead_code)]
pub fn config_override(&self, name: &'static str, scopes: Scopes) {
self.scopes.upsert_sync(name, (scopes, true));
}
pub fn scopes(&self, name: &str) -> Scopes {
self.scopes.read_sync(name, |_, (s, _)| *s).unwrap_or(Scopes::all())
}
pub fn expect(&self, name: &'static str, token: &Token, scopes: Scopes) {
self.scopes
.entry_sync(name)
.and_modify(|(s, overridden)| {
if s.intersects(scopes) {
if !*overridden {
*s &= scopes;
}
} else {
let verb = if *overridden { "configured" } else { "deduced" };
let msg = format!(
"{}{name} was {verb} to be {s} but scope seems to be {scopes}",
self.namespace
);
warn(ErrorKey::Scopes).weak().msg(msg).loc(token).push();
}
})
.or_insert((scopes, false));
}
}