circomspect_program_structure/intermediate_representation/
variable_meta.rs

1use std::fmt;
2use std::collections::HashSet;
3
4use super::ir::{AccessType, Meta, VariableName};
5
6/// A variable use (a variable, component or signal read or write).
7#[derive(Clone, Hash, PartialEq, Eq)]
8pub struct VariableUse {
9    meta: Meta,
10    name: VariableName,
11    access: Vec<AccessType>,
12}
13
14impl VariableUse {
15    pub fn new(meta: &Meta, name: &VariableName, access: &[AccessType]) -> VariableUse {
16        VariableUse { meta: meta.clone(), name: name.clone(), access: access.to_owned() }
17    }
18
19    pub fn meta(&self) -> &Meta {
20        &self.meta
21    }
22
23    pub fn name(&self) -> &VariableName {
24        &self.name
25    }
26
27    pub fn access(&self) -> &Vec<AccessType> {
28        &self.access
29    }
30}
31
32impl fmt::Display for VariableUse {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        write!(f, "{}", self.name)?;
35        for access in &self.access {
36            write!(f, "{access}")?;
37        }
38        Ok(())
39    }
40}
41
42pub type VariableUses = HashSet<VariableUse>;
43
44pub trait VariableMeta {
45    /// Compute variables read/written by the node. Must be called before either
46    /// of the getters are called. To avoid interior mutability this needs to be
47    /// called again whenever the node is mutated in a way that may invalidate
48    /// the cached variable use.
49    fn cache_variable_use(&mut self);
50
51    /// Get the set of variables read by the IR node.
52    #[must_use]
53    fn locals_read(&self) -> &VariableUses;
54
55    /// Get the set of variables written by the IR node.
56    #[must_use]
57    fn locals_written(&self) -> &VariableUses;
58
59    /// Get the set of signals read by the IR node. Note that this does not
60    /// include signals belonging to sub-components.
61    #[must_use]
62    fn signals_read(&self) -> &VariableUses;
63
64    /// Get the set of signals written by the IR node. Note that this does not
65    /// include signals belonging to sub-components.
66    #[must_use]
67    fn signals_written(&self) -> &VariableUses;
68
69    /// Get the set of components read by the IR node. Note that a component
70    /// read is typically a signal read for a signal exported by the component.
71    #[must_use]
72    fn components_read(&self) -> &VariableUses;
73
74    /// Get the set of components written by the IR node. Note that a component
75    /// write may either be a component initialization, or a signal write for a
76    /// signal exported by the component.
77    #[must_use]
78    fn components_written(&self) -> &VariableUses;
79
80    /// Get the set of variables read by the IR node. Note that this is simply
81    /// the union of all locals, signals, and components read by the node.
82    #[must_use]
83    fn variables_read<'a>(&'a self) -> Box<dyn Iterator<Item = &'a VariableUse> + 'a> {
84        let locals_read = self.locals_read().iter();
85        let signals_read = self.signals_read().iter();
86        let components_read = self.components_read().iter();
87        Box::new(locals_read.chain(signals_read).chain(components_read))
88    }
89
90    /// Get the set of variables written by the IR node. Note that this is
91    /// simply the union of all locals, signals, and components written.
92    #[must_use]
93    fn variables_written<'a>(&'a self) -> Box<dyn Iterator<Item = &'a VariableUse> + 'a> {
94        let locals_written = self.locals_written().iter();
95        let signals_written = self.signals_written().iter();
96        let components_written = self.components_written().iter();
97        Box::new(locals_written.chain(signals_written).chain(components_written))
98    }
99
100    /// Get the set of variables either read or written by the IR node.
101    #[must_use]
102    fn variables_used<'a>(&'a self) -> Box<dyn Iterator<Item = &'a VariableUse> + 'a> {
103        Box::new(self.variables_read().chain(self.variables_written()))
104    }
105}
106
107#[derive(Default, Clone)]
108pub struct VariableKnowledge {
109    locals_read: Option<VariableUses>,
110    locals_written: Option<VariableUses>,
111    signals_read: Option<VariableUses>,
112    signals_written: Option<VariableUses>,
113    components_read: Option<VariableUses>,
114    components_written: Option<VariableUses>,
115}
116
117impl VariableKnowledge {
118    #[must_use]
119    pub fn new() -> VariableKnowledge {
120        VariableKnowledge::default()
121    }
122
123    pub fn set_locals_read(&mut self, uses: &VariableUses) -> &mut VariableKnowledge {
124        self.locals_read = Some(uses.clone());
125        self
126    }
127
128    pub fn set_locals_written(&mut self, uses: &VariableUses) -> &mut VariableKnowledge {
129        self.locals_written = Some(uses.clone());
130        self
131    }
132
133    pub fn set_signals_read(&mut self, uses: &VariableUses) -> &mut VariableKnowledge {
134        self.signals_read = Some(uses.clone());
135        self
136    }
137
138    pub fn set_signals_written(&mut self, uses: &VariableUses) -> &mut VariableKnowledge {
139        self.signals_written = Some(uses.clone());
140        self
141    }
142
143    pub fn set_components_read(&mut self, uses: &VariableUses) -> &mut VariableKnowledge {
144        self.components_read = Some(uses.clone());
145        self
146    }
147
148    pub fn set_components_written(&mut self, uses: &VariableUses) -> &mut VariableKnowledge {
149        self.components_written = Some(uses.clone());
150        self
151    }
152
153    #[must_use]
154    pub fn locals_read(&self) -> &VariableUses {
155        self.locals_read.as_ref().expect("variable knowledge must be initialized before it is read")
156    }
157
158    #[must_use]
159    pub fn locals_written(&self) -> &VariableUses {
160        self.locals_written
161            .as_ref()
162            .expect("variable knowledge must be initialized before it is read")
163    }
164
165    #[must_use]
166    pub fn signals_read(&self) -> &VariableUses {
167        self.signals_read
168            .as_ref()
169            .expect("variable knowledge must be initialized before it is read")
170    }
171
172    #[must_use]
173    pub fn signals_written(&self) -> &VariableUses {
174        self.signals_written
175            .as_ref()
176            .expect("variable knowledge must be initialized before it is read")
177    }
178
179    #[must_use]
180    pub fn components_read(&self) -> &VariableUses {
181        self.components_read
182            .as_ref()
183            .expect("variable knowledge must be initialized before it is read")
184    }
185
186    #[must_use]
187    pub fn components_written(&self) -> &VariableUses {
188        self.components_written
189            .as_ref()
190            .expect("variable knowledge must be initialized before it is read")
191    }
192
193    #[must_use]
194    pub fn variables_read<'a>(&'a self) -> Box<dyn Iterator<Item = &'a VariableUse> + 'a> {
195        let locals_read = self.locals_read().iter();
196        let signals_read = self.signals_read().iter();
197        let components_read = self.components_read().iter();
198        Box::new(locals_read.chain(signals_read).chain(components_read))
199    }
200
201    #[must_use]
202    pub fn variables_written<'a>(&'a self) -> Box<dyn Iterator<Item = &'a VariableUse> + 'a> {
203        let locals_written = self.locals_written().iter();
204        let signals_written = self.signals_written().iter();
205        let components_written = self.components_written().iter();
206        Box::new(locals_written.chain(signals_written).chain(components_written))
207    }
208
209    #[must_use]
210    pub fn variables_used<'a>(&'a self) -> Box<dyn Iterator<Item = &'a VariableUse> + 'a> {
211        let variables_read = self.variables_read();
212        let variables_written = self.variables_written();
213        Box::new(variables_read.chain(variables_written))
214    }
215}