circomspect_program_structure/abstract_syntax_tree/
expression_impl.rs

1use std::fmt::{Debug, Display, Error, Formatter};
2
3use super::ast::*;
4use super::expression_builders::build_anonymous_component;
5
6impl Expression {
7    pub fn meta(&self) -> &Meta {
8        use Expression::*;
9        match self {
10            InfixOp { meta, .. }
11            | PrefixOp { meta, .. }
12            | InlineSwitchOp { meta, .. }
13            | Variable { meta, .. }
14            | ParallelOp { meta, .. }
15            | Number(meta, ..)
16            | Call { meta, .. }
17            | AnonymousComponent { meta, .. }
18            | ArrayInLine { meta, .. }
19            | Tuple { meta, .. } => meta,
20        }
21    }
22    pub fn meta_mut(&mut self) -> &mut Meta {
23        use Expression::*;
24        match self {
25            InfixOp { meta, .. }
26            | PrefixOp { meta, .. }
27            | InlineSwitchOp { meta, .. }
28            | Variable { meta, .. }
29            | ParallelOp { meta, .. }
30            | Number(meta, ..)
31            | Call { meta, .. }
32            | AnonymousComponent { meta, .. }
33            | ArrayInLine { meta, .. }
34            | Tuple { meta, .. } => meta,
35        }
36    }
37
38    pub fn is_array(&self) -> bool {
39        use Expression::*;
40        matches!(self, ArrayInLine { .. })
41    }
42
43    pub fn is_infix(&self) -> bool {
44        use Expression::*;
45        matches!(self, InfixOp { .. })
46    }
47
48    pub fn is_prefix(&self) -> bool {
49        use Expression::*;
50        matches!(self, PrefixOp { .. })
51    }
52
53    pub fn is_switch(&self) -> bool {
54        use Expression::*;
55        matches!(self, InlineSwitchOp { .. })
56    }
57
58    pub fn is_variable(&self) -> bool {
59        use Expression::*;
60        matches!(self, Variable { .. })
61    }
62
63    pub fn is_number(&self) -> bool {
64        use Expression::*;
65        matches!(self, Number(..))
66    }
67
68    pub fn is_call(&self) -> bool {
69        use Expression::*;
70        matches!(self, Call { .. })
71    }
72
73    pub fn is_parallel(&self) -> bool {
74        use Expression::*;
75        matches!(self, ParallelOp { .. })
76    }
77
78    pub fn is_tuple(&self) -> bool {
79        use Expression::*;
80        matches!(self, Tuple { .. })
81    }
82
83    pub fn is_anonymous_component(&self) -> bool {
84        use Expression::*;
85        matches!(self, AnonymousComponent { .. })
86    }
87
88    pub fn make_anonymous_parallel(self) -> Expression {
89        use Expression::*;
90        match self {
91            AnonymousComponent { meta, id, params, signals, names, .. } => {
92                build_anonymous_component(meta, id, params, signals, names, true)
93            }
94            _ => self,
95        }
96    }
97}
98
99impl FillMeta for Expression {
100    fn fill(&mut self, file_id: usize, element_id: &mut usize) {
101        use Expression::*;
102        self.meta_mut().elem_id = *element_id;
103        *element_id += 1;
104        match self {
105            Tuple { meta, values } => fill_tuple(meta, values, file_id, element_id),
106            Number(meta, _) => fill_number(meta, file_id, element_id),
107            Variable { meta, access, .. } => fill_variable(meta, access, file_id, element_id),
108            InfixOp { meta, lhe, rhe, .. } => fill_infix(meta, lhe, rhe, file_id, element_id),
109            PrefixOp { meta, rhe, .. } => fill_prefix(meta, rhe, file_id, element_id),
110            ParallelOp { meta, rhe, .. } => fill_parallel(meta, rhe, file_id, element_id),
111            InlineSwitchOp { meta, cond, if_false, if_true, .. } => {
112                fill_inline_switch_op(meta, cond, if_true, if_false, file_id, element_id)
113            }
114            Call { meta, args, .. } => fill_call(meta, args, file_id, element_id),
115            ArrayInLine { meta, values, .. } => {
116                fill_array_inline(meta, values, file_id, element_id)
117            }
118            AnonymousComponent { meta, params, signals, .. } => {
119                fill_anonymous_component(meta, params, signals, file_id, element_id)
120            }
121        }
122    }
123}
124
125fn fill_number(meta: &mut Meta, file_id: usize, _element_id: &mut usize) {
126    meta.set_file_id(file_id);
127}
128
129fn fill_variable(meta: &mut Meta, access: &mut [Access], file_id: usize, element_id: &mut usize) {
130    meta.set_file_id(file_id);
131    for acc in access {
132        if let Access::ArrayAccess(e) = acc {
133            e.fill(file_id, element_id)
134        }
135    }
136}
137
138fn fill_infix(
139    meta: &mut Meta,
140    lhe: &mut Expression,
141    rhe: &mut Expression,
142    file_id: usize,
143    element_id: &mut usize,
144) {
145    meta.set_file_id(file_id);
146    lhe.fill(file_id, element_id);
147    rhe.fill(file_id, element_id);
148}
149
150fn fill_prefix(meta: &mut Meta, rhe: &mut Expression, file_id: usize, element_id: &mut usize) {
151    meta.set_file_id(file_id);
152    rhe.fill(file_id, element_id);
153}
154
155fn fill_inline_switch_op(
156    meta: &mut Meta,
157    cond: &mut Expression,
158    if_true: &mut Expression,
159    if_false: &mut Expression,
160    file_id: usize,
161    element_id: &mut usize,
162) {
163    meta.set_file_id(file_id);
164    cond.fill(file_id, element_id);
165    if_true.fill(file_id, element_id);
166    if_false.fill(file_id, element_id);
167}
168
169fn fill_call(meta: &mut Meta, args: &mut [Expression], file_id: usize, element_id: &mut usize) {
170    meta.set_file_id(file_id);
171    for a in args {
172        a.fill(file_id, element_id);
173    }
174}
175
176fn fill_array_inline(
177    meta: &mut Meta,
178    values: &mut [Expression],
179    file_id: usize,
180    element_id: &mut usize,
181) {
182    meta.set_file_id(file_id);
183    for v in values {
184        v.fill(file_id, element_id);
185    }
186}
187
188fn fill_anonymous_component(
189    meta: &mut Meta,
190    params: &mut [Expression],
191    signals: &mut [Expression],
192    file_id: usize,
193    element_id: &mut usize,
194) {
195    meta.set_file_id(file_id);
196    for param in params {
197        param.fill(file_id, element_id);
198    }
199    for signal in signals {
200        signal.fill(file_id, element_id);
201    }
202}
203
204fn fill_tuple(meta: &mut Meta, values: &mut [Expression], file_id: usize, element_id: &mut usize) {
205    meta.set_file_id(file_id);
206    for value in values {
207        value.fill(file_id, element_id);
208    }
209}
210
211fn fill_parallel(meta: &mut Meta, rhe: &mut Expression, file_id: usize, element_id: &mut usize) {
212    meta.set_file_id(file_id);
213    rhe.fill(file_id, element_id);
214}
215
216impl Debug for Expression {
217    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
218        use Expression::*;
219        match self {
220            InfixOp { .. } => write!(f, "Expression::InfixOp"),
221            PrefixOp { .. } => write!(f, "Expression::PrefixOp"),
222            InlineSwitchOp { .. } => write!(f, "Expression::InlineSwitchOp"),
223            Variable { .. } => write!(f, "Expression::Variable"),
224            ParallelOp { .. } => write!(f, "Expression::ParallelOp"),
225            Number(..) => write!(f, "Expression::Number"),
226            Call { .. } => write!(f, "Expression::Call"),
227            AnonymousComponent { .. } => write!(f, "Expression::AnonymousComponent"),
228            ArrayInLine { .. } => write!(f, "Expression::ArrayInline"),
229            Tuple { .. } => write!(f, "Expression::Tuple"),
230        }
231    }
232}
233
234impl Display for Expression {
235    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
236        use Expression::*;
237        match self {
238            Tuple { values, .. } => write!(f, "({})", vec_to_string(values)),
239            Number(_, value) => write!(f, "{value}"),
240            Variable { name, access, .. } => {
241                write!(f, "{name}")?;
242                for access in access {
243                    write!(f, "{access}")?;
244                }
245                Ok(())
246            }
247            ParallelOp { rhe, .. } => write!(f, "parallel {rhe}"),
248            InfixOp { lhe, infix_op, rhe, .. } => write!(f, "({lhe} {infix_op} {rhe})"),
249            PrefixOp { prefix_op, rhe, .. } => write!(f, "{prefix_op}({rhe})"),
250            InlineSwitchOp { cond, if_true, if_false, .. } => {
251                write!(f, "({cond}? {if_true} : {if_false})")
252            }
253            Call { id, args, .. } => write!(f, "{id}({})", vec_to_string(args)),
254            ArrayInLine { values, .. } => write!(f, "[{}]", vec_to_string(values)),
255            AnonymousComponent { id, params, signals, names, .. } => {
256                write!(f, "{id}({})({})", vec_to_string(params), signals_to_string(names, signals))
257            }
258        }
259    }
260}
261
262impl Display for ExpressionInfixOpcode {
263    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
264        use ExpressionInfixOpcode::*;
265        match self {
266            Mul => f.write_str("*"),
267            Div => f.write_str("/"),
268            Add => f.write_str("+"),
269            Sub => f.write_str("-"),
270            Pow => f.write_str("**"),
271            IntDiv => f.write_str("\\"),
272            Mod => f.write_str("%"),
273            ShiftL => f.write_str("<<"),
274            ShiftR => f.write_str(">>"),
275            LesserEq => f.write_str("<="),
276            GreaterEq => f.write_str(">="),
277            Lesser => f.write_str("<"),
278            Greater => f.write_str(">"),
279            Eq => f.write_str("=="),
280            NotEq => f.write_str("!="),
281            BoolOr => f.write_str("||"),
282            BoolAnd => f.write_str("&&"),
283            BitOr => f.write_str("|"),
284            BitAnd => f.write_str("&"),
285            BitXor => f.write_str("^"),
286        }
287    }
288}
289
290impl Display for ExpressionPrefixOpcode {
291    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
292        use ExpressionPrefixOpcode::*;
293        match self {
294            Sub => f.write_str("-"),
295            BoolNot => f.write_str("!"),
296            Complement => f.write_str("~"),
297        }
298    }
299}
300
301impl Display for Access {
302    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
303        use Access::*;
304        match self {
305            ArrayAccess(index) => write!(f, "[{index}]"),
306            ComponentAccess(name) => write!(f, ".{name}"),
307        }
308    }
309}
310
311fn vec_to_string(elems: &[Expression]) -> String {
312    elems.iter().map(|arg| arg.to_string()).collect::<Vec<String>>().join(", ")
313}
314
315fn signals_to_string(names: &Option<Vec<(AssignOp, String)>>, signals: &[Expression]) -> String {
316    if let Some(names) = names {
317        names
318            .iter()
319            .zip(signals.iter())
320            .map(|((op, name), signal)| format!("{name} {op} {signal}"))
321            .collect::<Vec<_>>()
322    } else {
323        signals.iter().map(|signal| signal.to_string()).collect::<Vec<_>>()
324    }
325    .join(", ")
326}