use crate::obj::DefStructFieldFreeParamObj;
use crate::prelude::*;
use std::collections::HashMap;
#[derive(Clone)]
pub struct FreeParamCollection {
pub params: HashMap<String, Vec<FreeParamTypeAndLineFile>>,
}
#[derive(Clone, Debug)]
pub struct FreeParamTypeAndLineFile {
pub kind: ParamObjType,
pub line_file: LineFile,
}
impl FreeParamCollection {
pub fn new() -> Self {
FreeParamCollection {
params: HashMap::new(),
}
}
pub fn clear(&mut self) {
self.params.clear();
}
fn push_param(
&mut self,
name: String,
kind: ParamObjType,
line_file: LineFile,
) -> Result<(), RuntimeError> {
let stack = self.params.entry(name.clone()).or_default();
if stack.iter().any(|b| b.kind == kind) {
return Err(RuntimeError::from(ParseRuntimeError(
RuntimeErrorStruct::new_with_msg_and_line_file(
format!(
"free parameter `{}` is already bound as {:?} in an active scope",
name, kind
),
line_file,
),
)));
}
stack.push(FreeParamTypeAndLineFile { kind, line_file });
Ok(())
}
pub fn begin_scope(
&mut self,
kind: ParamObjType,
names: &[String],
line_file: LineFile,
) -> Result<(), RuntimeError> {
for n in names {
self.push_param(n.clone(), kind, line_file.clone())?;
}
Ok(())
}
pub fn end_scope(&mut self, kind: ParamObjType, names: &[String]) {
for n in names {
let Some(stack) = self.params.get_mut(n) else {
panic!("free param stack missing for `{}` on end_scope", n);
};
let Some(top) = stack.pop() else {
panic!("free param stack for `{}` empty on end_scope", n);
};
debug_assert_eq!(top.kind, kind);
if stack.is_empty() {
self.params.remove(n);
}
}
}
pub fn name_is_in_any_free_param_map(&self, name: &str) -> bool {
self.params
.get(name)
.map_or(false, |stack| !stack.is_empty())
}
pub fn resolve_identifier_to_free_param_obj(&self, name: &str) -> Obj {
if !self.name_is_in_any_free_param_map(name) {
return Identifier::new(name.to_string()).into();
}
let Some(stack) = self.params.get(name) else {
return Identifier::new(name.to_string()).into();
};
let Some(top) = stack.last() else {
return Identifier::new(name.to_string()).into();
};
match top.kind {
ParamObjType::Forall => ForallFreeParamObj::new(name.to_string()).into(),
ParamObjType::DefHeader => DefHeaderFreeParamObj::new(name.to_string()).into(),
ParamObjType::Exist => ExistFreeParamObj::new(name.to_string()).into(),
ParamObjType::SetBuilder => SetBuilderFreeParamObj::new(name.to_string()).into(),
ParamObjType::FnSet => FnSetFreeParamObj::new(name.to_string()).into(),
ParamObjType::Induc => ByInducFreeParamObj::new(name.to_string()).into(),
ParamObjType::DefAlgo => DefAlgoFreeParamObj::new(name.to_string()).into(),
ParamObjType::DefStructField => {
DefStructFieldFreeParamObj::new(name.to_string()).into()
}
ParamObjType::Identifier => Identifier::new(name.to_string()).into(),
}
}
}