1use log::trace;
2use num_traits::Zero;
3use std::collections::HashSet;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6
7use circom_algebra::modular_arithmetic;
8
9use super::declarations::Declarations;
10use super::degree_meta::{Degree, DegreeEnvironment, DegreeMeta, DegreeRange};
11use super::ir::*;
12use super::type_meta::TypeMeta;
13use super::value_meta::{ValueEnvironment, ValueMeta, ValueReduction};
14use super::variable_meta::{VariableMeta, VariableUse, VariableUses};
15
16impl Expression {
17 #[must_use]
18 pub fn meta(&self) -> &Meta {
19 use Expression::*;
20 match self {
21 InfixOp { meta, .. }
22 | PrefixOp { meta, .. }
23 | SwitchOp { meta, .. }
24 | Variable { meta, .. }
25 | Number(meta, ..)
26 | Call { meta, .. }
27 | InlineArray { meta, .. }
28 | Update { meta, .. }
29 | Access { meta, .. }
30 | Phi { meta, .. } => meta,
31 }
32 }
33
34 #[must_use]
35 pub fn meta_mut(&mut self) -> &mut Meta {
36 use Expression::*;
37 match self {
38 InfixOp { meta, .. }
39 | PrefixOp { meta, .. }
40 | SwitchOp { meta, .. }
41 | Variable { meta, .. }
42 | Number(meta, ..)
43 | Call { meta, .. }
44 | InlineArray { meta, .. }
45 | Update { meta, .. }
46 | Access { meta, .. }
47 | Phi { meta, .. } => meta,
48 }
49 }
50}
51
52impl PartialEq for Expression {
54 fn eq(&self, other: &Expression) -> bool {
55 use Expression::*;
56 match (self, other) {
57 (
58 InfixOp { lhe: self_lhe, infix_op: self_op, rhe: self_rhe, .. },
59 InfixOp { lhe: other_lhe, infix_op: other_op, rhe: other_rhe, .. },
60 ) => self_op == other_op && self_lhe == other_lhe && self_rhe == other_rhe,
61 (
62 PrefixOp { prefix_op: self_op, rhe: self_rhe, .. },
63 PrefixOp { prefix_op: other_op, rhe: other_rhe, .. },
64 ) => self_op == other_op && self_rhe == other_rhe,
65 (
66 SwitchOp { cond: self_cond, if_true: self_true, if_false: self_false, .. },
67 SwitchOp { cond: other_cond, if_true: other_true, if_false: other_false, .. },
68 ) => self_cond == other_cond && self_true == other_true && self_false == other_false,
69 (Variable { name: self_name, .. }, Variable { name: other_name, .. }) => {
70 self_name == other_name
71 }
72 (Number(_, self_value), Number(_, other_value)) => self_value == other_value,
73 (
74 Call { name: self_id, args: self_args, .. },
75 Call { name: other_id, args: other_args, .. },
76 ) => self_id == other_id && self_args == other_args,
77 (InlineArray { values: self_values, .. }, InlineArray { values: other_values, .. }) => {
78 self_values == other_values
79 }
80 (
81 Update { var: self_var, access: self_access, rhe: self_rhe, .. },
82 Update { var: other_var, access: other_access, rhe: other_rhe, .. },
83 ) => self_var == other_var && self_access == other_access && self_rhe == other_rhe,
84 (
85 Access { var: self_var, access: self_access, .. },
86 Access { var: other_var, access: other_access, .. },
87 ) => self_var == other_var && self_access == other_access,
88 (Phi { args: self_args, .. }, Phi { args: other_args, .. }) => self_args == other_args,
89 _ => false,
90 }
91 }
92}
93
94impl Eq for Expression {}
95
96impl Hash for Expression {
97 fn hash<H: Hasher>(&self, state: &mut H) {
98 use Expression::*;
99 match self {
100 InfixOp { lhe, rhe, .. } => {
101 lhe.hash(state);
102 rhe.hash(state);
103 }
104 PrefixOp { rhe, .. } => {
105 rhe.hash(state);
106 }
107 SwitchOp { cond, if_true, if_false, .. } => {
108 cond.hash(state);
109 if_true.hash(state);
110 if_false.hash(state);
111 }
112 Variable { name, .. } => {
113 name.hash(state);
114 }
115 Call { args, .. } => {
116 args.hash(state);
117 }
118 InlineArray { values, .. } => {
119 values.hash(state);
120 }
121 Access { var, access, .. } => {
122 var.hash(state);
123 access.hash(state);
124 }
125 Update { var, access, rhe, .. } => {
126 var.hash(state);
127 access.hash(state);
128 rhe.hash(state);
129 }
130 Phi { args, .. } => {
131 args.hash(state);
132 }
133 Number(_, value) => {
134 value.hash(state);
135 }
136 }
137 }
138}
139
140impl DegreeMeta for Expression {
141 fn propagate_degrees(&mut self, env: &DegreeEnvironment) -> bool {
142 let mut result = false;
143
144 use Degree::*;
145 use Expression::*;
146 match self {
147 InfixOp { meta, lhe, rhe, infix_op } => {
148 result = result || lhe.propagate_degrees(env);
149 result = result || rhe.propagate_degrees(env);
150 let range = infix_op.propagate_degrees(lhe.degree(), rhe.degree());
151 if let Some(range) = range {
152 result = result || meta.degree_knowledge_mut().set_degree(&range);
153 }
154 result
155 }
156 PrefixOp { meta, rhe, prefix_op, .. } => {
157 result = result || rhe.propagate_degrees(env);
158 let range = prefix_op.propagate_degrees(rhe.degree());
159 if let Some(range) = range {
160 result = result || meta.degree_knowledge_mut().set_degree(&range);
161 }
162 result
163 }
164 SwitchOp { meta, cond, if_true, if_false, .. } => {
165 result = result || cond.propagate_degrees(env);
170 result = result || if_true.propagate_degrees(env);
171 result = result || if_false.propagate_degrees(env);
172 let Some(range) = cond.degree() else {
173 return result;
174 };
175 if range.is_constant() {
176 if let Some(range) =
178 DegreeRange::iter_opt([if_true.degree(), if_false.degree()])
179 {
180 result = result || meta.degree_knowledge_mut().set_degree(&range);
181 }
182 }
183 result
184 }
185 Variable { meta, name } => {
186 if let Some(range) = env.degree(name) {
187 result = result || meta.degree_knowledge_mut().set_degree(range);
188 }
189 result
190 }
191 Call { meta, args, .. } => {
192 for arg in args.iter_mut() {
193 result = result || arg.propagate_degrees(env);
194 }
195 if args.iter().all(|arg| {
199 if let Some(range) = arg.degree() {
200 range.is_constant()
201 } else {
202 false
203 }
204 }) {
205 result = result || meta.degree_knowledge_mut().set_degree(&Constant.into())
206 }
207 result
208 }
209 InlineArray { meta, values } => {
210 for value in values.iter_mut() {
212 result = result || value.propagate_degrees(env);
213 }
214 let range = DegreeRange::iter_opt(values.iter().map(|value| value.degree()));
215 if let Some(range) = range {
216 result = result || meta.degree_knowledge_mut().set_degree(&range);
217 }
218 result
219 }
220 Access { meta, var, access } => {
221 for access in access.iter_mut() {
223 if let AccessType::ArrayAccess(index) = access {
224 result = result || index.propagate_degrees(env);
225 }
226 }
227 if let Some(range) = env.degree(var) {
228 result = result || meta.degree_knowledge_mut().set_degree(range);
229 }
230 result
231 }
232 Update { meta, var, access, rhe, .. } => {
233 result = result || rhe.propagate_degrees(env);
235 for access in access.iter_mut() {
236 if let AccessType::ArrayAccess(index) = access {
237 result = result || index.propagate_degrees(env);
238 }
239 }
240 if env.degree(var).is_none() {
241 if let Some(range) = rhe.degree() {
243 result = result || meta.degree_knowledge_mut().set_degree(range);
244 }
245 } else {
246 let range = DegreeRange::iter_opt([env.degree(var), rhe.degree()]);
249 if let Some(range) = range {
250 result = result || meta.degree_knowledge_mut().set_degree(&range);
251 }
252 }
253 result
254 }
255 Phi { meta, args } => {
256 let range = DegreeRange::iter_opt(args.iter().map(|arg| env.degree(arg)));
258 if let Some(range) = range {
259 result = result || meta.degree_knowledge_mut().set_degree(&range);
260 }
261 result
262 }
263 Number(meta, _) => {
264 meta.degree_knowledge_mut().set_degree(&Constant.into())
266 }
267 }
268 }
269
270 fn degree(&self) -> Option<&DegreeRange> {
271 self.meta().degree_knowledge().degree()
272 }
273}
274
275impl TypeMeta for Expression {
276 fn propagate_types(&mut self, vars: &Declarations) {
277 use Expression::*;
278 match self {
279 InfixOp { lhe, rhe, .. } => {
280 lhe.propagate_types(vars);
281 rhe.propagate_types(vars);
282 }
283 PrefixOp { rhe, .. } => {
284 rhe.propagate_types(vars);
285 }
286 SwitchOp { cond, if_true, if_false, .. } => {
287 cond.propagate_types(vars);
288 if_true.propagate_types(vars);
289 if_false.propagate_types(vars);
290 }
291 Variable { meta, name } => {
292 if let Some(var_type) = vars.get_type(name) {
293 meta.type_knowledge_mut().set_variable_type(var_type);
294 }
295 }
296 Call { args, .. } => {
297 for arg in args {
298 arg.propagate_types(vars);
299 }
300 }
301 InlineArray { values, .. } => {
302 for value in values {
303 value.propagate_types(vars);
304 }
305 }
306 Access { meta, var, access } => {
307 for access in access.iter_mut() {
308 if let AccessType::ArrayAccess(index) = access {
309 index.propagate_types(vars);
310 }
311 }
312 if let Some(var_type) = vars.get_type(var) {
313 meta.type_knowledge_mut().set_variable_type(var_type);
314 }
315 }
316 Update { meta, var, access, rhe, .. } => {
317 rhe.propagate_types(vars);
318 for access in access.iter_mut() {
319 if let AccessType::ArrayAccess(index) = access {
320 index.propagate_types(vars);
321 }
322 }
323 if let Some(var_type) = vars.get_type(var) {
324 meta.type_knowledge_mut().set_variable_type(var_type);
325 }
326 }
327 Phi { .. } => {
328 }
330 Number(_, _) => {}
331 }
332 }
333
334 fn is_local(&self) -> bool {
335 self.meta().type_knowledge().is_local()
336 }
337
338 fn is_signal(&self) -> bool {
339 self.meta().type_knowledge().is_signal()
340 }
341
342 fn is_component(&self) -> bool {
343 self.meta().type_knowledge().is_component()
344 }
345
346 fn variable_type(&self) -> Option<&VariableType> {
347 self.meta().type_knowledge().variable_type()
348 }
349}
350
351impl VariableMeta for Expression {
352 fn cache_variable_use(&mut self) {
353 let mut locals_read = VariableUses::new();
354 let mut signals_read = VariableUses::new();
355 let mut components_read = VariableUses::new();
356
357 use Expression::*;
358 match self {
359 InfixOp { lhe, rhe, .. } => {
360 lhe.cache_variable_use();
361 rhe.cache_variable_use();
362 locals_read.extend(lhe.locals_read().iter().cloned());
363 locals_read.extend(rhe.locals_read().iter().cloned());
364 signals_read.extend(lhe.signals_read().iter().cloned());
365 signals_read.extend(rhe.signals_read().iter().cloned());
366 components_read.extend(lhe.components_read().iter().cloned());
367 components_read.extend(rhe.components_read().iter().cloned());
368 }
369 PrefixOp { rhe, .. } => {
370 rhe.cache_variable_use();
371 locals_read.extend(rhe.locals_read().iter().cloned());
372 signals_read.extend(rhe.signals_read().iter().cloned());
373 components_read.extend(rhe.components_read().iter().cloned());
374 }
375 SwitchOp { cond, if_true, if_false, .. } => {
376 cond.cache_variable_use();
377 if_true.cache_variable_use();
378 if_false.cache_variable_use();
379 locals_read.extend(cond.locals_read().clone());
380 locals_read.extend(if_true.locals_read().clone());
381 locals_read.extend(if_false.locals_read().clone());
382 signals_read.extend(cond.signals_read().clone());
383 signals_read.extend(if_true.signals_read().clone());
384 signals_read.extend(if_false.signals_read().clone());
385 components_read.extend(cond.components_read().clone());
386 components_read.extend(if_true.components_read().clone());
387 components_read.extend(if_false.components_read().clone());
388 }
389 Variable { meta, name } => {
390 match meta.type_knowledge().variable_type() {
391 Some(VariableType::Local) => {
392 trace!("adding `{name:?}` to local variables read");
393 locals_read.insert(VariableUse::new(meta, name, &Vec::new()));
394 }
395 Some(VariableType::Component | VariableType::AnonymousComponent) => {
396 trace!("adding `{name:?}` to components read");
397 components_read.insert(VariableUse::new(meta, name, &Vec::new()));
398 }
399 Some(VariableType::Signal(_, _)) => {
400 trace!("adding `{name:?}` to signals read");
401 signals_read.insert(VariableUse::new(meta, name, &Vec::new()));
402 }
403 None => {
404 trace!("variable `{name:?}` of unknown type read");
406 }
407 }
408 }
409 Call { args, .. } => {
410 for arg in args {
411 arg.cache_variable_use();
412 locals_read.extend(arg.locals_read().clone());
413 signals_read.extend(arg.signals_read().clone());
414 components_read.extend(arg.components_read().clone());
415 }
416 }
417 Phi { meta, args } => {
418 locals_read
419 .extend(args.iter().map(|name| VariableUse::new(meta, name, &Vec::new())));
420 }
421 InlineArray { values, .. } => {
422 for value in values {
423 value.cache_variable_use();
424 locals_read.extend(value.locals_read().clone());
425 signals_read.extend(value.signals_read().clone());
426 components_read.extend(value.components_read().clone());
427 }
428 }
429 Access { meta, var, access } => {
430 for access in access.iter_mut() {
432 if let AccessType::ArrayAccess(index) = access {
433 index.cache_variable_use();
434 locals_read.extend(index.locals_read().clone());
435 signals_read.extend(index.signals_read().clone());
436 components_read.extend(index.components_read().clone());
437 }
438 }
439 match meta.type_knowledge().variable_type() {
441 Some(VariableType::Local) => {
442 trace!("adding `{var:?}` to local variables read");
443 locals_read.insert(VariableUse::new(meta, var, access));
444 }
445 Some(VariableType::Component | VariableType::AnonymousComponent) => {
446 trace!("adding `{var:?}` to components read");
447 components_read.insert(VariableUse::new(meta, var, access));
448 }
449 Some(VariableType::Signal(_, _)) => {
450 trace!("adding `{var:?}` to signals read");
451 signals_read.insert(VariableUse::new(meta, var, access));
452 }
453 None => {
454 trace!("variable `{var:?}` of unknown type read");
456 }
457 }
458 }
459 Update { meta, var, access, rhe, .. } => {
460 rhe.cache_variable_use();
462 locals_read.extend(rhe.locals_read().iter().cloned());
463 signals_read.extend(rhe.signals_read().iter().cloned());
464 components_read.extend(rhe.components_read().iter().cloned());
465
466 for access in access.iter_mut() {
468 if let AccessType::ArrayAccess(index) = access {
469 index.cache_variable_use();
470 locals_read.extend(index.locals_read().clone());
471 signals_read.extend(index.signals_read().clone());
472 components_read.extend(index.components_read().clone());
473 }
474 }
475 match meta.type_knowledge().variable_type() {
477 Some(VariableType::Local) => {
478 trace!("adding `{var:?}` to local variables read");
479 locals_read.insert(VariableUse::new(meta, var, &Vec::new()));
480 }
481 Some(VariableType::Component | VariableType::AnonymousComponent) => {
482 trace!("adding `{var:?}` to components read");
483 components_read.insert(VariableUse::new(meta, var, &Vec::new()));
484 }
485 Some(VariableType::Signal(_, _)) => {
486 trace!("adding `{var:?}` to signals read");
487 signals_read.insert(VariableUse::new(meta, var, &Vec::new()));
488 }
489 None => {
490 trace!("variable `{var:?}` of unknown type read");
492 }
493 }
494 }
495 Number(_, _) => {}
496 }
497 self.meta_mut()
498 .variable_knowledge_mut()
499 .set_locals_read(&locals_read)
500 .set_locals_written(&VariableUses::new())
501 .set_signals_read(&signals_read)
502 .set_signals_written(&VariableUses::new())
503 .set_components_read(&components_read)
504 .set_components_written(&VariableUses::new());
505 }
506
507 fn locals_read(&self) -> &VariableUses {
508 self.meta().variable_knowledge().locals_read()
509 }
510
511 fn locals_written(&self) -> &VariableUses {
512 self.meta().variable_knowledge().locals_written()
513 }
514
515 fn signals_read(&self) -> &VariableUses {
516 self.meta().variable_knowledge().signals_read()
517 }
518
519 fn signals_written(&self) -> &VariableUses {
520 self.meta().variable_knowledge().signals_written()
521 }
522
523 fn components_read(&self) -> &VariableUses {
524 self.meta().variable_knowledge().components_read()
525 }
526
527 fn components_written(&self) -> &VariableUses {
528 self.meta().variable_knowledge().components_written()
529 }
530}
531
532impl ValueMeta for Expression {
533 fn propagate_values(&mut self, env: &mut ValueEnvironment) -> bool {
534 use Expression::*;
535 use ValueReduction::*;
536 match self {
537 InfixOp { meta, lhe, infix_op, rhe, .. } => {
538 let mut result = lhe.propagate_values(env) || rhe.propagate_values(env);
539 if let Some(value) = infix_op.propagate_values(lhe.value(), rhe.value(), env) {
540 result = result || meta.value_knowledge_mut().set_reduces_to(value)
541 }
542 result
543 }
544 PrefixOp { meta, prefix_op, rhe } => {
545 let mut result = rhe.propagate_values(env);
546 if let Some(value) = prefix_op.propagate_values(rhe.value(), env) {
547 result = result || meta.value_knowledge_mut().set_reduces_to(value)
548 }
549 result
550 }
551 SwitchOp { meta, cond, if_true, if_false } => {
552 let mut result = cond.propagate_values(env)
553 | if_true.propagate_values(env)
554 | if_false.propagate_values(env);
555 match (cond.value(), if_true.value(), if_false.value()) {
556 (
557 Some(Boolean { value: cond }),
559 Some(value),
560 _,
561 ) if *cond => {
562 result = result || meta.value_knowledge_mut().set_reduces_to(value.clone())
563 }
564 (
565 Some(Boolean { value: cond }),
567 _,
568 Some(value),
569 ) if !cond => {
570 result = result || meta.value_knowledge_mut().set_reduces_to(value.clone())
571 }
572 (
573 Some(FieldElement { value: cond }),
575 Some(value),
576 _,
577 ) if !cond.is_zero() => {
578 result = result || meta.value_knowledge_mut().set_reduces_to(value.clone())
579 }
580 (
581 Some(FieldElement { value: cond }),
583 _,
584 Some(value),
585 ) if cond.is_zero() => {
586 result = result || meta.value_knowledge_mut().set_reduces_to(value.clone())
587 }
588 _ => {}
589 }
590 result
591 }
592 Variable { meta, name, .. } => match env.get_variable(name) {
593 Some(value) => meta.value_knowledge_mut().set_reduces_to(value.clone()),
594 None => false,
595 },
596 Number(meta, value) => {
597 let value = FieldElement { value: value.clone() };
598 meta.value_knowledge_mut().set_reduces_to(value)
599 }
600 Call { args, .. } => {
601 let mut result = false;
603 for arg in args {
604 result = result || arg.propagate_values(env);
605 }
606 result
607 }
608 InlineArray { values, .. } => {
609 let mut result = false;
611 for value in values {
612 result = result || value.propagate_values(env);
613 }
614 result
615 }
616 Access { access, .. } => {
617 let mut result = false;
619 for access in access.iter_mut() {
620 if let AccessType::ArrayAccess(index) = access {
621 result = result || index.propagate_values(env);
622 }
623 }
624 result
625 }
626 Update { access, rhe, .. } => {
627 let mut result = rhe.propagate_values(env);
629 for access in access.iter_mut() {
630 if let AccessType::ArrayAccess(index) = access {
631 result = result || index.propagate_values(env);
632 }
633 }
634 result
635 }
636 Phi { meta, args, .. } => {
637 let values =
639 args.iter().map(|name| env.get_variable(name)).collect::<Option<HashSet<_>>>();
640 match values {
641 Some(values) if values.len() == 1 => {
642 let value = *values.iter().next().unwrap();
644 meta.value_knowledge_mut().set_reduces_to(value.clone())
645 }
646 _ => false,
647 }
648 }
649 }
650 }
651
652 fn is_constant(&self) -> bool {
653 self.value().is_some()
654 }
655
656 fn is_boolean(&self) -> bool {
657 matches!(self.value(), Some(ValueReduction::Boolean { .. }))
658 }
659
660 fn is_field_element(&self) -> bool {
661 matches!(self.value(), Some(ValueReduction::FieldElement { .. }))
662 }
663
664 fn value(&self) -> Option<&ValueReduction> {
665 self.meta().value_knowledge().get_reduces_to()
666 }
667}
668
669impl ExpressionInfixOpcode {
670 fn propagate_degrees(
671 &self,
672 lhr: Option<&DegreeRange>,
673 rhr: Option<&DegreeRange>,
674 ) -> Option<DegreeRange> {
675 if let (Some(lhr), Some(rhr)) = (lhr, rhr) {
676 use ExpressionInfixOpcode::*;
677 match self {
678 Add => Some(lhr.add(rhr)),
679 Sub => Some(lhr.infix_sub(rhr)),
680 Mul => Some(lhr.mul(rhr)),
681 Pow => Some(lhr.pow(rhr)),
682 Div => Some(lhr.div(rhr)),
683 IntDiv => Some(lhr.int_div(rhr)),
684 Mod => Some(lhr.modulo(rhr)),
685 ShiftL => Some(lhr.shift_left(rhr)),
686 ShiftR => Some(lhr.shift_right(rhr)),
687 Lesser => Some(lhr.lesser(rhr)),
688 Greater => Some(lhr.greater(rhr)),
689 LesserEq => Some(lhr.lesser_eq(rhr)),
690 GreaterEq => Some(lhr.greater_eq(rhr)),
691 Eq => Some(lhr.equal(rhr)),
692 NotEq => Some(lhr.not_equal(rhr)),
693 BitOr => Some(lhr.bit_or(rhr)),
694 BitXor => Some(lhr.bit_xor(rhr)),
695 BitAnd => Some(lhr.bit_and(rhr)),
696 BoolOr => Some(lhr.bool_or(rhr)),
697 BoolAnd => Some(lhr.bool_and(rhr)),
698 }
699 } else {
700 None
701 }
702 }
703
704 fn propagate_values(
705 &self,
706 lhv: Option<&ValueReduction>,
707 rhv: Option<&ValueReduction>,
708 env: &ValueEnvironment,
709 ) -> Option<ValueReduction> {
710 let p = env.prime();
711
712 use ValueReduction::*;
713 match (lhv, rhv) {
714 (Some(FieldElement { value: lhv }), Some(FieldElement { value: rhv })) => {
716 use ExpressionInfixOpcode::*;
717 match self {
718 Mul => {
719 let value = modular_arithmetic::mul(lhv, rhv, p);
720 Some(FieldElement { value })
721 }
722 Div => modular_arithmetic::div(lhv, rhv, p)
723 .ok()
724 .map(|value| FieldElement { value }),
725 Add => {
726 let value = modular_arithmetic::add(lhv, rhv, p);
727 Some(FieldElement { value })
728 }
729 Sub => {
730 let value = modular_arithmetic::sub(lhv, rhv, p);
731 Some(FieldElement { value })
732 }
733 Pow => {
734 let value = modular_arithmetic::pow(lhv, rhv, p);
735 Some(FieldElement { value })
736 }
737 IntDiv => modular_arithmetic::idiv(lhv, rhv, p)
738 .ok()
739 .map(|value| FieldElement { value }),
740 Mod => modular_arithmetic::mod_op(lhv, rhv, p)
741 .ok()
742 .map(|value| FieldElement { value }),
743 ShiftL => modular_arithmetic::shift_l(lhv, rhv, p)
744 .ok()
745 .map(|value| FieldElement { value }),
746 ShiftR => modular_arithmetic::shift_r(lhv, rhv, p)
747 .ok()
748 .map(|value| FieldElement { value }),
749 LesserEq => {
750 let value = modular_arithmetic::lesser_eq(lhv, rhv, p);
751 Some(Boolean { value: modular_arithmetic::as_bool(&value, p) })
752 }
753 GreaterEq => {
754 let value = modular_arithmetic::greater_eq(lhv, rhv, p);
755 Some(Boolean { value: modular_arithmetic::as_bool(&value, p) })
756 }
757 Lesser => {
758 let value = modular_arithmetic::lesser(lhv, rhv, p);
759 Some(Boolean { value: modular_arithmetic::as_bool(&value, p) })
760 }
761 Greater => {
762 let value = modular_arithmetic::greater(lhv, rhv, p);
763 Some(Boolean { value: modular_arithmetic::as_bool(&value, p) })
764 }
765 Eq => {
766 let value = modular_arithmetic::eq(lhv, rhv, p);
767 Some(Boolean { value: modular_arithmetic::as_bool(&value, p) })
768 }
769 NotEq => {
770 let value = modular_arithmetic::not_eq(lhv, rhv, p);
771 Some(Boolean { value: modular_arithmetic::as_bool(&value, p) })
772 }
773 BitOr => {
774 let value = modular_arithmetic::bit_or(lhv, rhv, p);
775 Some(FieldElement { value })
776 }
777 BitAnd => {
778 let value = modular_arithmetic::bit_and(lhv, rhv, p);
779 Some(FieldElement { value })
780 }
781 BitXor => {
782 let value = modular_arithmetic::bit_xor(lhv, rhv, p);
783 Some(FieldElement { value })
784 }
785 _ => None,
788 }
789 }
790 (Some(Boolean { value: lhv }), Some(Boolean { value: rhv })) => {
792 use ExpressionInfixOpcode::*;
793 match self {
794 BoolAnd => Some(Boolean { value: *lhv && *rhv }),
795 BoolOr => Some(Boolean { value: *lhv || *rhv }),
796 _ => None,
799 }
800 }
801 _ => None,
802 }
803 }
804}
805
806impl ExpressionPrefixOpcode {
807 fn propagate_degrees(&self, range: Option<&DegreeRange>) -> Option<DegreeRange> {
808 if let Some(range) = range {
809 use ExpressionPrefixOpcode::*;
810 match self {
811 Sub => Some(range.prefix_sub()),
812 Complement => Some(range.complement()),
813 BoolNot => Some(range.bool_not()),
814 }
815 } else {
816 None
817 }
818 }
819
820 fn propagate_values(
821 &self,
822 rhe: Option<&ValueReduction>,
823 env: &ValueEnvironment,
824 ) -> Option<ValueReduction> {
825 let p = env.prime();
826
827 use ValueReduction::*;
828 match rhe {
829 Some(FieldElement { value: arg }) => {
831 use ExpressionPrefixOpcode::*;
832 match self {
833 Sub => {
834 let value = modular_arithmetic::prefix_sub(arg, p);
835 Some(FieldElement { value })
836 }
837 Complement => {
838 let value = modular_arithmetic::complement_256(arg, p);
839 Some(FieldElement { value })
840 }
841 _ => None,
844 }
845 }
846 Some(Boolean { value: arg }) => {
848 use ExpressionPrefixOpcode::*;
849 match self {
850 BoolNot => Some(Boolean { value: !arg }),
851 _ => None,
854 }
855 }
856 None => None,
857 }
858 }
859}
860
861impl fmt::Debug for Expression {
862 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
863 use Expression::*;
864 match self {
865 Number(_, value) => write!(f, "{value}"),
866 Variable { name, .. } => {
867 write!(f, "{name:?}")
868 }
869 InfixOp { lhe, infix_op, rhe, .. } => write!(f, "({lhe:?} {infix_op} {rhe:?})"),
870 PrefixOp { prefix_op, rhe, .. } => write!(f, "({prefix_op}{rhe:?})"),
871 SwitchOp { cond, if_true, if_false, .. } => {
872 write!(f, "({cond:?}? {if_true:?} : {if_false:?})")
873 }
874 Call { name: id, args, .. } => write!(f, "{}({})", id, vec_to_debug(args, ", ")),
875 InlineArray { values, .. } => write!(f, "[{}]", vec_to_debug(values, ", ")),
876 Access { var, access, .. } => {
877 let access = access
878 .iter()
879 .map(|access| match access {
880 AccessType::ArrayAccess(index) => format!("{index:?}"),
881 AccessType::ComponentAccess(name) => name.clone(),
882 })
883 .collect::<Vec<_>>()
884 .join(", ");
885 write!(f, "access({var:?}, [{access}])")
886 }
887 Update { var, access, rhe, .. } => {
888 let access = access
889 .iter()
890 .map(|access| match access {
891 AccessType::ArrayAccess(index) => format!("{index:?}"),
892 AccessType::ComponentAccess(name) => name.clone(),
893 })
894 .collect::<Vec<_>>()
895 .join(", ");
896 write!(f, "update({var:?}, [{access}], {rhe:?})")
897 }
898 Phi { args, .. } => write!(f, "φ({})", vec_to_debug(args, ", ")),
899 }
900 }
901}
902
903impl fmt::Display for Expression {
904 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
905 use Expression::*;
906 match self {
907 Number(_, value) => write!(f, "{value}"),
908 Variable { name, .. } => {
909 write!(f, "{name}")
910 }
911 InfixOp { lhe, infix_op, rhe, .. } => write!(f, "({lhe} {infix_op} {rhe})"),
912 PrefixOp { prefix_op, rhe, .. } => write!(f, "{prefix_op}({rhe})"),
913 SwitchOp { cond, if_true, if_false, .. } => {
914 write!(f, "({cond}? {if_true} : {if_false})")
915 }
916 Call { name: id, args, .. } => write!(f, "{}({})", id, vec_to_display(args, ", ")),
917 InlineArray { values, .. } => write!(f, "[{}]", vec_to_display(values, ", ")),
918 Access { var, access, .. } => {
919 write!(f, "{var}")?;
920 for access in access {
921 write!(f, "{access}")?;
922 }
923 Ok(())
924 }
925 Update { rhe, .. } => {
926 write!(f, "{rhe}")
930 }
931 Phi { args, .. } => write!(f, "φ({})", vec_to_display(args, ", ")),
932 }
933 }
934}
935
936impl fmt::Display for ExpressionInfixOpcode {
937 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
938 use ExpressionInfixOpcode::*;
939 match self {
940 Mul => f.write_str("*"),
941 Div => f.write_str("/"),
942 Add => f.write_str("+"),
943 Sub => f.write_str("-"),
944 Pow => f.write_str("**"),
945 IntDiv => f.write_str("\\"),
946 Mod => f.write_str("%"),
947 ShiftL => f.write_str("<<"),
948 ShiftR => f.write_str(">>"),
949 LesserEq => f.write_str("<="),
950 GreaterEq => f.write_str(">="),
951 Lesser => f.write_str("<"),
952 Greater => f.write_str(">"),
953 Eq => f.write_str("=="),
954 NotEq => f.write_str("!="),
955 BoolOr => f.write_str("||"),
956 BoolAnd => f.write_str("&&"),
957 BitOr => f.write_str("|"),
958 BitAnd => f.write_str("&"),
959 BitXor => f.write_str("^"),
960 }
961 }
962}
963
964impl fmt::Display for ExpressionPrefixOpcode {
965 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
966 use ExpressionPrefixOpcode::*;
967 match self {
968 Sub => f.write_str("-"),
969 BoolNot => f.write_str("!"),
970 Complement => f.write_str("~"),
971 }
972 }
973}
974
975impl fmt::Debug for AccessType {
976 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
977 use AccessType::*;
978 match self {
979 ArrayAccess(index) => write!(f, "{index:?}"),
980 ComponentAccess(name) => write!(f, "{name:?}"),
981 }
982 }
983}
984
985impl fmt::Display for AccessType {
986 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
987 use AccessType::*;
988 match self {
989 ArrayAccess(index) => write!(f, "[{index}]"),
990 ComponentAccess(name) => write!(f, ".{name}"),
991 }
992 }
993}
994
995#[must_use]
996fn vec_to_debug<T: fmt::Debug>(elems: &[T], sep: &str) -> String {
997 elems.iter().map(|elem| format!("{elem:?}")).collect::<Vec<String>>().join(sep)
998}
999
1000#[must_use]
1001fn vec_to_display<T: fmt::Display>(elems: &[T], sep: &str) -> String {
1002 elems.iter().map(|elem| format!("{elem}")).collect::<Vec<String>>().join(sep)
1003}
1004
1005#[cfg(test)]
1006mod tests {
1007 use crate::constants::{UsefulConstants, Curve};
1008
1009 use super::*;
1010
1011 #[test]
1012 fn test_propagate_values() {
1013 use Expression::*;
1014 use ExpressionInfixOpcode::*;
1015 use ValueReduction::*;
1016 let mut lhe = Number(Meta::default(), 7u64.into());
1017 let mut rhe = Variable { meta: Meta::default(), name: VariableName::from_string("v") };
1018 let constants = UsefulConstants::new(&Curve::default());
1019 let mut env = ValueEnvironment::new(&constants);
1020 env.add_variable(&VariableName::from_string("v"), &FieldElement { value: 3u64.into() });
1021 lhe.propagate_values(&mut env);
1022 rhe.propagate_values(&mut env);
1023
1024 let mut expr = InfixOp {
1026 meta: Meta::default(),
1027 infix_op: Mul,
1028 lhe: Box::new(lhe.clone()),
1029 rhe: Box::new(rhe.clone()),
1030 };
1031 expr.propagate_values(&mut env.clone());
1032 assert_eq!(expr.value(), Some(&FieldElement { value: 21u64.into() }));
1033
1034 let mut expr = InfixOp {
1036 meta: Meta::default(),
1037 infix_op: Add,
1038 lhe: Box::new(lhe.clone()),
1039 rhe: Box::new(rhe.clone()),
1040 };
1041 expr.propagate_values(&mut env.clone());
1042 assert_eq!(expr.value(), Some(&FieldElement { value: 10u64.into() }));
1043
1044 let mut expr = InfixOp {
1046 meta: Meta::default(),
1047 infix_op: IntDiv,
1048 lhe: Box::new(lhe.clone()),
1049 rhe: Box::new(rhe.clone()),
1050 };
1051 expr.propagate_values(&mut env.clone());
1052 assert_eq!(expr.value(), Some(&FieldElement { value: 2u64.into() }));
1053 }
1054}