Skip to main content

litex/runtime/
runtime_parsing_free_param_collection.rs

1use crate::prelude::*;
2use std::collections::HashMap;
3
4#[derive(Clone)]
5pub struct FreeParamCollection {
6    pub params: HashMap<String, Vec<FreeParamTypeAndLineFile>>,
7}
8
9#[derive(Clone, Debug)]
10pub struct FreeParamTypeAndLineFile {
11    pub kind: ParamObjType,
12    pub line_file: LineFile,
13}
14
15impl FreeParamCollection {
16    pub fn new() -> Self {
17        FreeParamCollection {
18            params: HashMap::new(),
19        }
20    }
21
22    pub fn clear(&mut self) {
23        self.params.clear();
24    }
25
26    fn push_param(
27        &mut self,
28        name: String,
29        kind: ParamObjType,
30        line_file: LineFile,
31    ) -> Result<(), RuntimeError> {
32        let stack = self.params.entry(name.clone()).or_default();
33        if stack.iter().any(|b| b.kind == kind) {
34            return Err(RuntimeError::from(ParseRuntimeError(
35                RuntimeErrorStruct::new(
36                    None,
37                    format!(
38                        "free parameter `{}` is already bound as {:?} in an active scope",
39                        name, kind
40                    ),
41                    line_file,
42                    None,
43                    vec![],
44                ),
45            )));
46        }
47        stack.push(FreeParamTypeAndLineFile { kind, line_file });
48        Ok(())
49    }
50
51    pub fn begin_scope(
52        &mut self,
53        kind: ParamObjType,
54        names: &[String],
55        line_file: LineFile,
56    ) -> Result<(), RuntimeError> {
57        for n in names {
58            self.push_param(n.clone(), kind, line_file.clone())?;
59        }
60        Ok(())
61    }
62
63    pub fn end_scope(&mut self, kind: ParamObjType, names: &[String]) {
64        for n in names {
65            let Some(stack) = self.params.get_mut(n) else {
66                panic!("free param stack missing for `{}` on end_scope", n);
67            };
68            let Some(top) = stack.pop() else {
69                panic!("free param stack for `{}` empty on end_scope", n);
70            };
71            debug_assert_eq!(top.kind, kind);
72            if stack.is_empty() {
73                self.params.remove(n);
74            }
75        }
76    }
77
78    pub fn name_is_in_any_free_param_map(&self, name: &str) -> bool {
79        self.params.get(name).map_or(false, |stack| !stack.is_empty())
80    }
81
82    pub fn resolve_identifier_to_free_param_obj(&self, name: &str) -> Obj {
83        if !self.name_is_in_any_free_param_map(name) {
84            return Identifier::new(name.to_string()).into();
85        }
86        let Some(stack) = self.params.get(name) else {
87            return Identifier::new(name.to_string()).into();
88        };
89        let Some(top) = stack.last() else {
90            return Identifier::new(name.to_string()).into();
91        };
92        match top.kind {
93            ParamObjType::Forall => ForallFreeParamObj::new(name.to_string()).into(),
94            ParamObjType::DefHeader => DefHeaderFreeParamObj::new(name.to_string()).into(),
95            ParamObjType::Exist => ExistFreeParamObj::new(name.to_string()).into(),
96            ParamObjType::SetBuilder => SetBuilderFreeParamObj::new(name.to_string()).into(),
97            ParamObjType::FnSet => FnSetFreeParamObj::new(name.to_string()).into(),
98            ParamObjType::Sum => SumFreeParamObj::new(name.to_string()).into(),
99            ParamObjType::Induc => ByInducFreeParamObj::new(name.to_string()).into(),
100            ParamObjType::DefAlgo => DefAlgoFreeParamObj::new(name.to_string()).into(),
101            ParamObjType::Product => ProductFreeParamObj::new(name.to_string()).into(),
102            ParamObjType::Identifier => Identifier::new(name.to_string()).into(),
103        }
104    }
105}