use std::collections::HashSet;
use crate::pr;
use crate::{Result, Span};
pub(super) struct ConstantValidator {
constants: HashSet<pr::Path>,
}
impl ConstantValidator {
pub fn new() -> Self {
Self {
constants: Default::default(),
}
}
pub fn save_const(&mut self, path: pr::Path) {
self.constants.insert(path);
}
pub fn validate_is_const(&mut self, expr: &pr::Expr) -> Result<(), Option<Span>> {
let r = match &expr.kind {
pr::ExprKind::Literal(_) => Ok(()),
pr::ExprKind::Ident(_) => match expr.target.as_ref().unwrap() {
pr::Ref::Global(target_fq) => {
if self.constants.contains(target_fq) {
Ok(())
} else {
Err(expr.span)
}
}
pr::Ref::Local { .. } => Err(expr.span),
},
pr::ExprKind::Lookup { base, .. } => self.validate_is_const(base),
pr::ExprKind::Tuple(fields) => fields
.iter()
.find_map(|f| self.validate_is_const(&f.expr).err())
.map(Err)
.unwrap_or(Ok(())),
pr::ExprKind::Array(items) => items
.iter()
.find_map(|i| self.validate_is_const(i).err())
.map(Err)
.unwrap_or(Ok(())),
pr::ExprKind::Variant(variant) => variant
.inner
.as_ref()
.map(|i| self.validate_is_const(i))
.unwrap_or(Ok(())),
pr::ExprKind::Call(_)
| pr::ExprKind::Func(_)
| pr::ExprKind::Match(_)
| pr::ExprKind::If(_)
| pr::ExprKind::VarBinding(_) => Err(expr.span),
pr::ExprKind::TypeAnnotation(_)
| pr::ExprKind::Range(_)
| pr::ExprKind::Binary(_)
| pr::ExprKind::Unary(_)
| pr::ExprKind::Nested(_)
| pr::ExprKind::FString(_)
| pr::ExprKind::FuncShort(_) => unreachable!(),
};
r.map_err(|s| s.or(expr.span))
}
}