circomspect_program_structure/abstract_syntax_tree/
statement_impl.rs

1use std::fmt::{Debug, Display, Error, Formatter};
2
3use super::ast::*;
4
5impl Statement {
6    pub fn get_meta(&self) -> &Meta {
7        use Statement::*;
8        match self {
9            IfThenElse { meta, .. }
10            | While { meta, .. }
11            | Return { meta, .. }
12            | Declaration { meta, .. }
13            | Substitution { meta, .. }
14            | MultiSubstitution { meta, .. }
15            | LogCall { meta, .. }
16            | Block { meta, .. }
17            | Assert { meta, .. }
18            | ConstraintEquality { meta, .. }
19            | InitializationBlock { meta, .. } => meta,
20        }
21    }
22    pub fn get_mut_meta(&mut self) -> &mut Meta {
23        use Statement::*;
24        match self {
25            IfThenElse { meta, .. }
26            | While { meta, .. }
27            | Return { meta, .. }
28            | Declaration { meta, .. }
29            | Substitution { meta, .. }
30            | MultiSubstitution { meta, .. }
31            | LogCall { meta, .. }
32            | Block { meta, .. }
33            | Assert { meta, .. }
34            | ConstraintEquality { meta, .. }
35            | InitializationBlock { meta, .. } => meta,
36        }
37    }
38
39    pub fn is_if_then_else(&self) -> bool {
40        use Statement::*;
41        matches!(self, IfThenElse { .. })
42    }
43
44    pub fn is_while(&self) -> bool {
45        use Statement::*;
46        matches!(self, While { .. })
47    }
48
49    pub fn is_return(&self) -> bool {
50        use Statement::*;
51        matches!(self, Return { .. })
52    }
53
54    pub fn is_initialization_block(&self) -> bool {
55        use Statement::*;
56        matches!(self, InitializationBlock { .. })
57    }
58
59    pub fn is_declaration(&self) -> bool {
60        use Statement::*;
61        matches!(self, Declaration { .. })
62    }
63
64    pub fn is_substitution(&self) -> bool {
65        use Statement::*;
66        matches!(self, Substitution { .. })
67    }
68
69    pub fn is_multi_substitution(&self) -> bool {
70        use Statement::*;
71        matches!(self, MultiSubstitution { .. })
72    }
73
74    pub fn is_constraint_equality(&self) -> bool {
75        use Statement::*;
76        matches!(self, ConstraintEquality { .. })
77    }
78
79    pub fn is_log_call(&self) -> bool {
80        use Statement::*;
81        matches!(self, LogCall { .. })
82    }
83
84    pub fn is_block(&self) -> bool {
85        use Statement::*;
86        matches!(self, Block { .. })
87    }
88
89    pub fn is_assert(&self) -> bool {
90        use Statement::*;
91        matches!(self, Assert { .. })
92    }
93}
94
95impl FillMeta for Statement {
96    fn fill(&mut self, file_id: usize, element_id: &mut usize) {
97        use Statement::*;
98        self.get_mut_meta().elem_id = *element_id;
99        *element_id += 1;
100        match self {
101            IfThenElse { meta, cond, if_case, else_case, .. } => {
102                fill_conditional(meta, cond, if_case, else_case, file_id, element_id)
103            }
104            While { meta, cond, stmt } => fill_while(meta, cond, stmt, file_id, element_id),
105            Return { meta, value } => fill_return(meta, value, file_id, element_id),
106            InitializationBlock { meta, initializations, .. } => {
107                fill_initialization(meta, initializations, file_id, element_id)
108            }
109            Declaration { meta, dimensions, .. } => {
110                fill_declaration(meta, dimensions, file_id, element_id)
111            }
112            Substitution { meta, access, rhe, .. } => {
113                fill_substitution(meta, access, rhe, file_id, element_id)
114            }
115            MultiSubstitution { meta, lhe, rhe, .. } => {
116                fill_multi_substitution(meta, lhe, rhe, file_id, element_id);
117            }
118            ConstraintEquality { meta, lhe, rhe } => {
119                fill_constraint_equality(meta, lhe, rhe, file_id, element_id)
120            }
121            LogCall { meta, args, .. } => fill_log_call(meta, args, file_id, element_id),
122            Block { meta, stmts, .. } => fill_block(meta, stmts, file_id, element_id),
123            Assert { meta, arg, .. } => fill_assert(meta, arg, file_id, element_id),
124        }
125    }
126}
127
128fn fill_conditional(
129    meta: &mut Meta,
130    cond: &mut Expression,
131    if_case: &mut Statement,
132    else_case: &mut Option<Box<Statement>>,
133    file_id: usize,
134    element_id: &mut usize,
135) {
136    meta.set_file_id(file_id);
137    cond.fill(file_id, element_id);
138    if_case.fill(file_id, element_id);
139    if let Option::Some(s) = else_case {
140        s.fill(file_id, element_id);
141    }
142}
143
144fn fill_while(
145    meta: &mut Meta,
146    cond: &mut Expression,
147    stmt: &mut Statement,
148    file_id: usize,
149    element_id: &mut usize,
150) {
151    meta.set_file_id(file_id);
152    cond.fill(file_id, element_id);
153    stmt.fill(file_id, element_id);
154}
155
156fn fill_return(meta: &mut Meta, value: &mut Expression, file_id: usize, element_id: &mut usize) {
157    meta.set_file_id(file_id);
158    value.fill(file_id, element_id);
159}
160
161fn fill_initialization(
162    meta: &mut Meta,
163    initializations: &mut [Statement],
164    file_id: usize,
165    element_id: &mut usize,
166) {
167    meta.set_file_id(file_id);
168    for init in initializations {
169        init.fill(file_id, element_id);
170    }
171}
172
173fn fill_declaration(
174    meta: &mut Meta,
175    dimensions: &mut [Expression],
176    file_id: usize,
177    element_id: &mut usize,
178) {
179    meta.set_file_id(file_id);
180    for d in dimensions {
181        d.fill(file_id, element_id);
182    }
183}
184
185fn fill_substitution(
186    meta: &mut Meta,
187    access: &mut [Access],
188    rhe: &mut Expression,
189    file_id: usize,
190    element_id: &mut usize,
191) {
192    meta.set_file_id(file_id);
193    rhe.fill(file_id, element_id);
194    for a in access {
195        if let Access::ArrayAccess(e) = a {
196            e.fill(file_id, element_id);
197        }
198    }
199}
200
201fn fill_multi_substitution(
202    meta: &mut Meta,
203    lhe: &mut Expression,
204    rhe: &mut Expression,
205    file_id: usize,
206    element_id: &mut usize,
207) {
208    meta.set_file_id(file_id);
209    rhe.fill(file_id, element_id);
210    lhe.fill(file_id, element_id);
211}
212
213fn fill_constraint_equality(
214    meta: &mut Meta,
215    lhe: &mut Expression,
216    rhe: &mut Expression,
217    file_id: usize,
218    element_id: &mut usize,
219) {
220    meta.set_file_id(file_id);
221    lhe.fill(file_id, element_id);
222    rhe.fill(file_id, element_id);
223}
224
225fn fill_log_call(
226    meta: &mut Meta,
227    args: &mut Vec<LogArgument>,
228    file_id: usize,
229    element_id: &mut usize,
230) {
231    meta.set_file_id(file_id);
232    for arg in args {
233        if let LogArgument::LogExp(e) = arg {
234            e.fill(file_id, element_id);
235        }
236    }
237}
238
239fn fill_block(meta: &mut Meta, stmts: &mut [Statement], file_id: usize, element_id: &mut usize) {
240    meta.set_file_id(file_id);
241    for s in stmts {
242        s.fill(file_id, element_id);
243    }
244}
245
246fn fill_assert(meta: &mut Meta, arg: &mut Expression, file_id: usize, element_id: &mut usize) {
247    meta.set_file_id(file_id);
248    arg.fill(file_id, element_id);
249}
250
251impl Debug for Statement {
252    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
253        use Statement::*;
254        match self {
255            IfThenElse { .. } => write!(f, "Statement::IfThenElse"),
256            While { .. } => write!(f, "Statement::While"),
257            Return { .. } => write!(f, "Statement::Return"),
258            Declaration { .. } => write!(f, "Statement::Declaration"),
259            Substitution { .. } => write!(f, "Statement::Substitution"),
260            MultiSubstitution { .. } => write!(f, "Statement::MultiSubstitution"),
261            LogCall { .. } => write!(f, "Statement::LogCall"),
262            Block { .. } => write!(f, "Statement::Block"),
263            Assert { .. } => write!(f, "Statement::Assert"),
264            ConstraintEquality { .. } => write!(f, "Statement::ConstraintEquality"),
265            InitializationBlock { .. } => write!(f, "Statement::InitializationBlock"),
266        }
267    }
268}
269
270impl Display for Statement {
271    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
272        use Statement::*;
273        match self {
274            IfThenElse { cond, else_case, .. } => match else_case {
275                Some(_) => write!(f, "if {cond} else"),
276                None => write!(f, "if {cond}"),
277            },
278            While { cond, .. } => write!(f, "while {cond}"),
279            Return { value, .. } => write!(f, "return {value}"),
280            Declaration { name, xtype, .. } => write!(f, "{xtype} {name}"),
281            Substitution { var, access, op, rhe, .. } => {
282                write!(f, "{var}")?;
283                for access in access {
284                    write!(f, "{access}")?;
285                }
286                write!(f, " {op} {rhe}")
287            }
288            MultiSubstitution { lhe, op, rhe, .. } => write!(f, "{lhe} {op} {rhe}"),
289            LogCall { args, .. } => write!(f, "log({})", vec_to_string(args)),
290            Block { .. } => Ok(()),
291            Assert { arg, .. } => write!(f, "assert({arg})"),
292            ConstraintEquality { lhe, rhe, .. } => write!(f, "{lhe} === {rhe}"),
293            InitializationBlock { .. } => Ok(()),
294        }
295    }
296}
297
298impl Display for AssignOp {
299    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
300        use AssignOp::*;
301        match self {
302            AssignVar => write!(f, "="),
303            AssignSignal => write!(f, "<--"),
304            AssignConstraintSignal => write!(f, "<=="),
305        }
306    }
307}
308
309impl Display for VariableType {
310    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
311        use SignalType::*;
312        use VariableType::*;
313        match self {
314            Var => write!(f, "var"),
315            Signal(signal_type, tag_list) => {
316                if matches!(signal_type, Intermediate) {
317                    write!(f, "signal")?;
318                } else {
319                    write!(f, "signal {signal_type}")?;
320                }
321                if !tag_list.is_empty() {
322                    write!(f, " {{{}}}", tag_list.join("}} {{"))
323                } else {
324                    Ok(())
325                }
326            }
327            Component => write!(f, "component"),
328            AnonymousComponent => write!(f, "anonymous component"),
329        }
330    }
331}
332
333impl Display for SignalType {
334    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
335        use SignalType::*;
336        match self {
337            Input => write!(f, "input"),
338            Output => write!(f, "output"),
339            Intermediate => write!(f, ""),
340        }
341    }
342}
343
344impl Display for LogArgument {
345    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
346        use LogArgument::*;
347        match self {
348            LogStr(message) => write!(f, "{message}"),
349            LogExp(value) => write!(f, "{value}"),
350        }
351    }
352}
353
354fn vec_to_string<T: ToString>(elems: &[T]) -> String {
355    elems.iter().map(|arg| arg.to_string()).collect::<Vec<String>>().join(", ")
356}