Skip to main content

litex/runtime/
runtime_parsing_free_param_collection.rs

1use crate::obj::DefStructFieldFreeParamObj;
2use crate::prelude::*;
3use std::collections::HashMap;
4
5#[derive(Clone)]
6pub struct FreeParamCollection {
7    pub params: HashMap<String, Vec<FreeParamTypeAndLineFile>>,
8}
9
10#[derive(Clone, Debug)]
11pub struct FreeParamTypeAndLineFile {
12    pub kind: ParamObjType,
13    pub line_file: LineFile,
14}
15
16impl FreeParamCollection {
17    pub fn new() -> Self {
18        FreeParamCollection {
19            params: HashMap::new(),
20        }
21    }
22
23    pub fn clear(&mut self) {
24        self.params.clear();
25    }
26
27    fn push_param(
28        &mut self,
29        name: String,
30        kind: ParamObjType,
31        line_file: LineFile,
32    ) -> Result<(), RuntimeError> {
33        let stack = self.params.entry(name.clone()).or_default();
34        if stack.iter().any(|b| b.kind == kind) {
35            return Err(RuntimeError::from(ParseRuntimeError(
36                RuntimeErrorStruct::new_with_msg_and_line_file(
37                    format!(
38                        "free parameter `{}` is already bound as {:?} in an active scope",
39                        name, kind
40                    ),
41                    line_file,
42                ),
43            )));
44        }
45        stack.push(FreeParamTypeAndLineFile { kind, line_file });
46        Ok(())
47    }
48
49    pub fn begin_scope(
50        &mut self,
51        kind: ParamObjType,
52        names: &[String],
53        line_file: LineFile,
54    ) -> Result<(), RuntimeError> {
55        for n in names {
56            self.push_param(n.clone(), kind, line_file.clone())?;
57        }
58        Ok(())
59    }
60
61    pub fn end_scope(&mut self, kind: ParamObjType, names: &[String]) {
62        for n in names {
63            let Some(stack) = self.params.get_mut(n) else {
64                panic!("free param stack missing for `{}` on end_scope", n);
65            };
66            let Some(top) = stack.pop() else {
67                panic!("free param stack for `{}` empty on end_scope", n);
68            };
69            debug_assert_eq!(top.kind, kind);
70            if stack.is_empty() {
71                self.params.remove(n);
72            }
73        }
74    }
75
76    pub fn name_is_in_any_free_param_map(&self, name: &str) -> bool {
77        self.params
78            .get(name)
79            .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::Induc => ByInducFreeParamObj::new(name.to_string()).into(),
99            ParamObjType::DefAlgo => DefAlgoFreeParamObj::new(name.to_string()).into(),
100            ParamObjType::DefStructField => {
101                DefStructFieldFreeParamObj::new(name.to_string()).into()
102            }
103            ParamObjType::Identifier => Identifier::new(name.to_string()).into(),
104        }
105    }
106}