1use crate::circuit::classical::{ClassicalType, ClassicalValue, ClassicalVar};
55use crate::circuit::error::CircuitError;
56use std::collections::{BTreeSet, HashMap};
57use std::num::NonZeroU32;
58use std::ops::{BitAnd, BitOr, BitXor, Not};
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62pub enum ClassicalUnaryOp {
63 Not,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
69pub enum ClassicalBinaryOp {
70 And,
72 Or,
74 Xor,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
80pub enum ClassicalCompareOp {
81 Eq,
83 Ne,
85 Lt,
87 Le,
89 Gt,
91 Ge,
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
97pub enum ClassicalCast {
98 BitToBool,
100 BitVecToUInt,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Hash)]
110pub struct ClassicalExpr {
111 node: Box<ClassicalExprNode>,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, Hash)]
119pub struct ClassicalExprNode {
120 ty: ClassicalType,
121 kind: ClassicalExprKind,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Hash)]
130pub enum ClassicalExprKind {
131 Var(ClassicalVar),
133 Value(ClassicalValue),
135 BoolLiteral(bool),
137 BitLiteral(bool),
139 UIntLiteral {
141 width: NonZeroU32,
143 value: u128,
145 },
146 BitVecLiteral {
148 width: NonZeroU32,
150 value: u128,
152 },
153 Unary {
155 op: ClassicalUnaryOp,
157 expr: ClassicalExpr,
159 },
160 Binary {
162 op: ClassicalBinaryOp,
164 lhs: ClassicalExpr,
166 rhs: ClassicalExpr,
168 },
169 Compare {
171 op: ClassicalCompareOp,
173 lhs: ClassicalExpr,
175 rhs: ClassicalExpr,
177 },
178 Cast {
180 cast: ClassicalCast,
182 expr: ClassicalExpr,
184 },
185 Select {
187 condition: ClassicalExpr,
189 then_expr: ClassicalExpr,
191 else_expr: ClassicalExpr,
193 },
194 ExtractBit {
196 value: ClassicalExpr,
198 index: u32,
200 },
201 ExtractBits {
203 value: ClassicalExpr,
205 offset: u32,
207 width: NonZeroU32,
209 },
210 Concat {
212 parts: Box<[ClassicalExpr]>,
214 },
215 PackBits {
217 bits: Box<[ClassicalExpr]>,
219 },
220}
221
222impl ClassicalExpr {
223 pub fn var(var: ClassicalVar) -> Self {
225 Self {
226 node: Box::new(ClassicalExprNode {
227 ty: var.ty(),
228 kind: ClassicalExprKind::Var(var),
229 }),
230 }
231 }
232
233 pub fn value(value: ClassicalValue) -> Self {
235 Self {
236 node: Box::new(ClassicalExprNode {
237 ty: value.ty(),
238 kind: ClassicalExprKind::Value(value),
239 }),
240 }
241 }
242
243 pub fn bool_literal(value: bool) -> Self {
245 Self {
246 node: Box::new(ClassicalExprNode {
247 ty: ClassicalType::Bool,
248 kind: ClassicalExprKind::BoolLiteral(value),
249 }),
250 }
251 }
252
253 pub fn bit_literal(value: bool) -> Self {
255 Self {
256 node: Box::new(ClassicalExprNode {
257 ty: ClassicalType::Bit,
258 kind: ClassicalExprKind::BitLiteral(value),
259 }),
260 }
261 }
262
263 pub fn uint_literal(width: u32, value: u128) -> Result<Self, CircuitError> {
267 let Some(width) = NonZeroU32::new(width) else {
268 return Err(CircuitError::InvalidOperation(
269 "UInt literal width must be non-zero".to_string(),
270 ));
271 };
272 if width.get() > 128 {
273 return Err(CircuitError::InvalidOperation(format!(
274 "UInt literal width {} exceeds the 128-bit literal limit",
275 width.get()
276 )));
277 }
278 if width.get() < 128 && value >= (1u128 << width.get()) {
279 return Err(CircuitError::InvalidOperation(format!(
280 "UInt literal value {value} does not fit in width {}",
281 width.get()
282 )));
283 }
284 Ok(Self {
285 node: Box::new(ClassicalExprNode {
286 ty: ClassicalType::UInt(width),
287 kind: ClassicalExprKind::UIntLiteral { width, value },
288 }),
289 })
290 }
291
292 pub fn bit_vec_literal(width: u32, value: u128) -> Result<Self, CircuitError> {
296 let Some(width) = NonZeroU32::new(width) else {
297 return Err(CircuitError::InvalidOperation(
298 "BitVec literal width must be non-zero".to_string(),
299 ));
300 };
301 if width.get() > 128 {
302 return Err(CircuitError::InvalidOperation(format!(
303 "BitVec literal width {} exceeds the 128-bit literal limit",
304 width.get()
305 )));
306 }
307 if width.get() < 128 && value >= (1u128 << width.get()) {
308 return Err(CircuitError::InvalidOperation(format!(
309 "BitVec literal value {value} does not fit in width {}",
310 width.get()
311 )));
312 }
313 Ok(Self {
314 node: Box::new(ClassicalExprNode {
315 ty: ClassicalType::BitVec(width),
316 kind: ClassicalExprKind::BitVecLiteral { width, value },
317 }),
318 })
319 }
320
321 pub fn ty(&self) -> ClassicalType {
323 self.node.ty
324 }
325
326 pub fn kind(&self) -> &ClassicalExprKind {
332 &self.node.kind
333 }
334
335 pub fn remap_classical_ids(
341 &self,
342 var_map: &HashMap<ClassicalVar, ClassicalVar>,
343 value_map: &HashMap<ClassicalValue, ClassicalValue>,
344 ) -> Result<Self, CircuitError> {
345 let kind = match &self.node.kind {
346 ClassicalExprKind::Var(var) => {
347 let mapped = var_map.get(var).copied().ok_or_else(|| {
348 CircuitError::InvalidOperation(format!(
349 "missing classical variable remap for id {}",
350 var.id()
351 ))
352 })?;
353 ClassicalExprKind::Var(mapped)
354 }
355 ClassicalExprKind::Value(value) => {
356 let mapped = value_map.get(value).copied().ok_or_else(|| {
357 CircuitError::InvalidOperation(format!(
358 "missing classical value remap for id {}",
359 value.index()
360 ))
361 })?;
362 ClassicalExprKind::Value(mapped)
363 }
364 ClassicalExprKind::BoolLiteral(value) => ClassicalExprKind::BoolLiteral(*value),
365 ClassicalExprKind::BitLiteral(value) => ClassicalExprKind::BitLiteral(*value),
366 ClassicalExprKind::UIntLiteral { width, value } => ClassicalExprKind::UIntLiteral {
367 width: *width,
368 value: *value,
369 },
370 ClassicalExprKind::BitVecLiteral { width, value } => ClassicalExprKind::BitVecLiteral {
371 width: *width,
372 value: *value,
373 },
374 ClassicalExprKind::Unary { op, expr } => ClassicalExprKind::Unary {
375 op: *op,
376 expr: expr.remap_classical_ids(var_map, value_map)?,
377 },
378 ClassicalExprKind::Binary { op, lhs, rhs } => ClassicalExprKind::Binary {
379 op: *op,
380 lhs: lhs.remap_classical_ids(var_map, value_map)?,
381 rhs: rhs.remap_classical_ids(var_map, value_map)?,
382 },
383 ClassicalExprKind::Compare { op, lhs, rhs } => ClassicalExprKind::Compare {
384 op: *op,
385 lhs: lhs.remap_classical_ids(var_map, value_map)?,
386 rhs: rhs.remap_classical_ids(var_map, value_map)?,
387 },
388 ClassicalExprKind::Cast { cast, expr } => ClassicalExprKind::Cast {
389 cast: *cast,
390 expr: expr.remap_classical_ids(var_map, value_map)?,
391 },
392 ClassicalExprKind::Select {
393 condition,
394 then_expr,
395 else_expr,
396 } => ClassicalExprKind::Select {
397 condition: condition.remap_classical_ids(var_map, value_map)?,
398 then_expr: then_expr.remap_classical_ids(var_map, value_map)?,
399 else_expr: else_expr.remap_classical_ids(var_map, value_map)?,
400 },
401 ClassicalExprKind::ExtractBit { value, index } => ClassicalExprKind::ExtractBit {
402 value: value.remap_classical_ids(var_map, value_map)?,
403 index: *index,
404 },
405 ClassicalExprKind::ExtractBits {
406 value,
407 offset,
408 width,
409 } => ClassicalExprKind::ExtractBits {
410 value: value.remap_classical_ids(var_map, value_map)?,
411 offset: *offset,
412 width: *width,
413 },
414 ClassicalExprKind::Concat { parts } => ClassicalExprKind::Concat {
415 parts: parts
416 .iter()
417 .map(|part| part.remap_classical_ids(var_map, value_map))
418 .collect::<Result<Vec<_>, _>>()?
419 .into_boxed_slice(),
420 },
421 ClassicalExprKind::PackBits { bits } => ClassicalExprKind::PackBits {
422 bits: bits
423 .iter()
424 .map(|bit| bit.remap_classical_ids(var_map, value_map))
425 .collect::<Result<Vec<_>, _>>()?
426 .into_boxed_slice(),
427 },
428 };
429
430 Ok(Self {
431 node: Box::new(ClassicalExprNode {
432 ty: self.node.ty,
433 kind,
434 }),
435 })
436 }
437
438 pub fn vars(&self) -> BTreeSet<ClassicalVar> {
440 let mut vars = BTreeSet::new();
441 self.collect_vars(&mut vars);
442 vars
443 }
444
445 pub fn values(&self) -> BTreeSet<ClassicalValue> {
447 let mut values = BTreeSet::new();
448 self.collect_values(&mut values);
449 values
450 }
451
452 pub fn collect_vars(&self, out: &mut BTreeSet<ClassicalVar>) {
454 match &self.node.kind {
455 ClassicalExprKind::Var(var) => {
456 out.insert(*var);
457 }
458 ClassicalExprKind::Value(_) => {}
459 ClassicalExprKind::BoolLiteral(_)
460 | ClassicalExprKind::BitLiteral(_)
461 | ClassicalExprKind::UIntLiteral { .. }
462 | ClassicalExprKind::BitVecLiteral { .. } => {}
463 ClassicalExprKind::Unary { expr, .. } | ClassicalExprKind::Cast { expr, .. } => {
464 expr.collect_vars(out);
465 }
466 ClassicalExprKind::Binary { lhs, rhs, .. }
467 | ClassicalExprKind::Compare { lhs, rhs, .. } => {
468 lhs.collect_vars(out);
469 rhs.collect_vars(out);
470 }
471 ClassicalExprKind::Select {
472 condition,
473 then_expr,
474 else_expr,
475 } => {
476 condition.collect_vars(out);
477 then_expr.collect_vars(out);
478 else_expr.collect_vars(out);
479 }
480 ClassicalExprKind::ExtractBit { value, .. }
481 | ClassicalExprKind::ExtractBits { value, .. } => {
482 value.collect_vars(out);
483 }
484 ClassicalExprKind::Concat { parts } => {
485 for part in parts.iter() {
486 part.collect_vars(out);
487 }
488 }
489 ClassicalExprKind::PackBits { bits } => {
490 for bit in bits.iter() {
491 bit.collect_vars(out);
492 }
493 }
494 }
495 }
496
497 pub fn collect_values(&self, out: &mut BTreeSet<ClassicalValue>) {
499 match &self.node.kind {
500 ClassicalExprKind::Value(value) => {
501 out.insert(*value);
502 }
503 ClassicalExprKind::Var(_)
504 | ClassicalExprKind::BoolLiteral(_)
505 | ClassicalExprKind::BitLiteral(_)
506 | ClassicalExprKind::UIntLiteral { .. }
507 | ClassicalExprKind::BitVecLiteral { .. } => {}
508 ClassicalExprKind::Unary { expr, .. } | ClassicalExprKind::Cast { expr, .. } => {
509 expr.collect_values(out);
510 }
511 ClassicalExprKind::Binary { lhs, rhs, .. }
512 | ClassicalExprKind::Compare { lhs, rhs, .. } => {
513 lhs.collect_values(out);
514 rhs.collect_values(out);
515 }
516 ClassicalExprKind::Select {
517 condition,
518 then_expr,
519 else_expr,
520 } => {
521 condition.collect_values(out);
522 then_expr.collect_values(out);
523 else_expr.collect_values(out);
524 }
525 ClassicalExprKind::ExtractBit { value, .. }
526 | ClassicalExprKind::ExtractBits { value, .. } => {
527 value.collect_values(out);
528 }
529 ClassicalExprKind::Concat { parts } => {
530 for part in parts.iter() {
531 part.collect_values(out);
532 }
533 }
534 ClassicalExprKind::PackBits { bits } => {
535 for bit in bits.iter() {
536 bit.collect_values(out);
537 }
538 }
539 }
540 }
541
542 pub fn try_not(expr: impl Into<Self>) -> Result<Self, CircuitError> {
544 let expr = expr.into();
545 match expr.ty() {
546 ClassicalType::Bool | ClassicalType::Bit => Ok(Self {
547 node: Box::new(ClassicalExprNode {
548 ty: expr.ty(),
549 kind: ClassicalExprKind::Unary {
550 op: ClassicalUnaryOp::Not,
551 expr,
552 },
553 }),
554 }),
555 ty => Err(CircuitError::InvalidOperation(format!(
556 "not expects Bool or Bit, got {ty:?}"
557 ))),
558 }
559 }
560
561 pub fn try_and(lhs: impl Into<Self>, rhs: impl Into<Self>) -> Result<Self, CircuitError> {
563 let lhs = lhs.into();
564 let rhs = rhs.into();
565 let ty = lhs.ty();
566 if ty != rhs.ty() {
567 return Err(CircuitError::InvalidOperation(format!(
568 "binary operands must have the same type, got {:?} and {:?}",
569 lhs.ty(),
570 rhs.ty()
571 )));
572 }
573 match ty {
574 ClassicalType::Bool | ClassicalType::Bit => Ok(Self {
575 node: Box::new(ClassicalExprNode {
576 ty,
577 kind: ClassicalExprKind::Binary {
578 op: ClassicalBinaryOp::And,
579 lhs,
580 rhs,
581 },
582 }),
583 }),
584 ty => Err(CircuitError::InvalidOperation(format!(
585 "binary And expects Bool or Bit operands, got {ty:?}"
586 ))),
587 }
588 }
589
590 pub fn try_or(lhs: impl Into<Self>, rhs: impl Into<Self>) -> Result<Self, CircuitError> {
592 let lhs = lhs.into();
593 let rhs = rhs.into();
594 let ty = lhs.ty();
595 if ty != rhs.ty() {
596 return Err(CircuitError::InvalidOperation(format!(
597 "binary operands must have the same type, got {:?} and {:?}",
598 lhs.ty(),
599 rhs.ty()
600 )));
601 }
602 match ty {
603 ClassicalType::Bool | ClassicalType::Bit => Ok(Self {
604 node: Box::new(ClassicalExprNode {
605 ty,
606 kind: ClassicalExprKind::Binary {
607 op: ClassicalBinaryOp::Or,
608 lhs,
609 rhs,
610 },
611 }),
612 }),
613 ty => Err(CircuitError::InvalidOperation(format!(
614 "binary Or expects Bool or Bit operands, got {ty:?}"
615 ))),
616 }
617 }
618
619 pub fn try_xor(lhs: impl Into<Self>, rhs: impl Into<Self>) -> Result<Self, CircuitError> {
621 let lhs = lhs.into();
622 let rhs = rhs.into();
623 let ty = lhs.ty();
624 if ty != rhs.ty() {
625 return Err(CircuitError::InvalidOperation(format!(
626 "binary operands must have the same type, got {:?} and {:?}",
627 lhs.ty(),
628 rhs.ty()
629 )));
630 }
631 match ty {
632 ClassicalType::Bool | ClassicalType::Bit => Ok(Self {
633 node: Box::new(ClassicalExprNode {
634 ty,
635 kind: ClassicalExprKind::Binary {
636 op: ClassicalBinaryOp::Xor,
637 lhs,
638 rhs,
639 },
640 }),
641 }),
642 ty => Err(CircuitError::InvalidOperation(format!(
643 "binary Xor expects Bool or Bit operands, got {ty:?}"
644 ))),
645 }
646 }
647
648 pub fn eq(lhs: Self, rhs: Self) -> Result<Self, CircuitError> {
650 if lhs.ty() != rhs.ty() {
651 return Err(CircuitError::InvalidOperation(format!(
652 "comparison operands must have the same type, got {:?} and {:?}",
653 lhs.ty(),
654 rhs.ty()
655 )));
656 }
657 Ok(Self {
658 node: Box::new(ClassicalExprNode {
659 ty: ClassicalType::Bool,
660 kind: ClassicalExprKind::Compare {
661 op: ClassicalCompareOp::Eq,
662 lhs,
663 rhs,
664 },
665 }),
666 })
667 }
668
669 pub fn ne(lhs: Self, rhs: Self) -> Result<Self, CircuitError> {
671 if lhs.ty() != rhs.ty() {
672 return Err(CircuitError::InvalidOperation(format!(
673 "comparison operands must have the same type, got {:?} and {:?}",
674 lhs.ty(),
675 rhs.ty()
676 )));
677 }
678 Ok(Self {
679 node: Box::new(ClassicalExprNode {
680 ty: ClassicalType::Bool,
681 kind: ClassicalExprKind::Compare {
682 op: ClassicalCompareOp::Ne,
683 lhs,
684 rhs,
685 },
686 }),
687 })
688 }
689
690 pub fn lt(lhs: Self, rhs: Self) -> Result<Self, CircuitError> {
692 if lhs.ty() != rhs.ty() {
693 return Err(CircuitError::InvalidOperation(format!(
694 "comparison operands must have the same type, got {:?} and {:?}",
695 lhs.ty(),
696 rhs.ty()
697 )));
698 }
699 if !matches!(lhs.ty(), ClassicalType::UInt(_)) {
700 return Err(CircuitError::InvalidOperation(format!(
701 "ordered comparisons require UInt operands, got {:?}",
702 lhs.ty()
703 )));
704 }
705 Ok(Self {
706 node: Box::new(ClassicalExprNode {
707 ty: ClassicalType::Bool,
708 kind: ClassicalExprKind::Compare {
709 op: ClassicalCompareOp::Lt,
710 lhs,
711 rhs,
712 },
713 }),
714 })
715 }
716
717 pub fn le(lhs: Self, rhs: Self) -> Result<Self, CircuitError> {
719 if lhs.ty() != rhs.ty() {
720 return Err(CircuitError::InvalidOperation(format!(
721 "comparison operands must have the same type, got {:?} and {:?}",
722 lhs.ty(),
723 rhs.ty()
724 )));
725 }
726 if !matches!(lhs.ty(), ClassicalType::UInt(_)) {
727 return Err(CircuitError::InvalidOperation(format!(
728 "ordered comparisons require UInt operands, got {:?}",
729 lhs.ty()
730 )));
731 }
732 Ok(Self {
733 node: Box::new(ClassicalExprNode {
734 ty: ClassicalType::Bool,
735 kind: ClassicalExprKind::Compare {
736 op: ClassicalCompareOp::Le,
737 lhs,
738 rhs,
739 },
740 }),
741 })
742 }
743
744 pub fn gt(lhs: Self, rhs: Self) -> Result<Self, CircuitError> {
746 if lhs.ty() != rhs.ty() {
747 return Err(CircuitError::InvalidOperation(format!(
748 "comparison operands must have the same type, got {:?} and {:?}",
749 lhs.ty(),
750 rhs.ty()
751 )));
752 }
753 if !matches!(lhs.ty(), ClassicalType::UInt(_)) {
754 return Err(CircuitError::InvalidOperation(format!(
755 "ordered comparisons require UInt operands, got {:?}",
756 lhs.ty()
757 )));
758 }
759 Ok(Self {
760 node: Box::new(ClassicalExprNode {
761 ty: ClassicalType::Bool,
762 kind: ClassicalExprKind::Compare {
763 op: ClassicalCompareOp::Gt,
764 lhs,
765 rhs,
766 },
767 }),
768 })
769 }
770
771 pub fn ge(lhs: Self, rhs: Self) -> Result<Self, CircuitError> {
773 if lhs.ty() != rhs.ty() {
774 return Err(CircuitError::InvalidOperation(format!(
775 "comparison operands must have the same type, got {:?} and {:?}",
776 lhs.ty(),
777 rhs.ty()
778 )));
779 }
780 if !matches!(lhs.ty(), ClassicalType::UInt(_)) {
781 return Err(CircuitError::InvalidOperation(format!(
782 "ordered comparisons require UInt operands, got {:?}",
783 lhs.ty()
784 )));
785 }
786 Ok(Self {
787 node: Box::new(ClassicalExprNode {
788 ty: ClassicalType::Bool,
789 kind: ClassicalExprKind::Compare {
790 op: ClassicalCompareOp::Ge,
791 lhs,
792 rhs,
793 },
794 }),
795 })
796 }
797
798 pub fn bit_to_bool(expr: Self) -> Result<Self, CircuitError> {
800 if expr.ty() != ClassicalType::Bit {
801 return Err(CircuitError::InvalidOperation(format!(
802 "bit_to_bool expects Bit, got {:?}",
803 expr.ty()
804 )));
805 }
806 Ok(Self {
807 node: Box::new(ClassicalExprNode {
808 ty: ClassicalType::Bool,
809 kind: ClassicalExprKind::Cast {
810 cast: ClassicalCast::BitToBool,
811 expr,
812 },
813 }),
814 })
815 }
816
817 pub fn bit_vec_to_uint(expr: Self) -> Result<Self, CircuitError> {
819 match expr.ty() {
820 ClassicalType::BitVec(width) => Ok(Self {
821 node: Box::new(ClassicalExprNode {
822 ty: ClassicalType::UInt(width),
823 kind: ClassicalExprKind::Cast {
824 cast: ClassicalCast::BitVecToUInt,
825 expr,
826 },
827 }),
828 }),
829 ty => Err(CircuitError::InvalidOperation(format!(
830 "bit_vec_to_uint expects BitVec, got {ty:?}"
831 ))),
832 }
833 }
834
835 pub fn to_bool(self) -> Result<Self, CircuitError> {
837 Self::bit_to_bool(self)
838 }
839
840 pub fn to_uint(self) -> Result<Self, CircuitError> {
842 Self::bit_vec_to_uint(self)
843 }
844
845 pub fn select(condition: Self, then_expr: Self, else_expr: Self) -> Result<Self, CircuitError> {
847 if condition.ty() != ClassicalType::Bool {
848 return Err(CircuitError::InvalidOperation(format!(
849 "select condition expects Bool, got {:?}",
850 condition.ty()
851 )));
852 }
853 if then_expr.ty() != else_expr.ty() {
854 return Err(CircuitError::InvalidOperation(format!(
855 "select branches must have the same type, got {:?} and {:?}",
856 then_expr.ty(),
857 else_expr.ty()
858 )));
859 }
860 Ok(Self {
861 node: Box::new(ClassicalExprNode {
862 ty: then_expr.ty(),
863 kind: ClassicalExprKind::Select {
864 condition,
865 then_expr,
866 else_expr,
867 },
868 }),
869 })
870 }
871
872 pub fn extract_bit(value: Self, index: u32) -> Result<Self, CircuitError> {
876 let width = match value.ty() {
877 ClassicalType::UInt(width) | ClassicalType::BitVec(width) => width.get(),
878 ty => {
879 return Err(CircuitError::InvalidOperation(format!(
880 "extract_bit expects UInt or BitVec, got {ty:?}"
881 )));
882 }
883 };
884 if index >= width {
885 return Err(CircuitError::InvalidOperation(format!(
886 "extract_bit index {index} out of bounds for width {width}"
887 )));
888 }
889 Ok(Self {
890 node: Box::new(ClassicalExprNode {
891 ty: ClassicalType::Bit,
892 kind: ClassicalExprKind::ExtractBit { value, index },
893 }),
894 })
895 }
896
897 pub fn extract_bits(value: Self, offset: u32, width: u32) -> Result<Self, CircuitError> {
901 let source_width = match value.ty() {
902 ClassicalType::UInt(width) | ClassicalType::BitVec(width) => width.get(),
903 ty => {
904 return Err(CircuitError::InvalidOperation(format!(
905 "extract_bits expects UInt or BitVec, got {ty:?}"
906 )));
907 }
908 };
909 let Some(width) = NonZeroU32::new(width) else {
910 return Err(CircuitError::InvalidOperation(
911 "extract_bits width must be non-zero".to_string(),
912 ));
913 };
914 let Some(end) = offset.checked_add(width.get()) else {
915 return Err(CircuitError::InvalidOperation(
916 "extract_bits range overflows u32".to_string(),
917 ));
918 };
919 if end > source_width {
920 return Err(CircuitError::InvalidOperation(format!(
921 "extract_bits range [{offset}, {end}) out of bounds for width {source_width}"
922 )));
923 }
924 Ok(Self {
925 node: Box::new(ClassicalExprNode {
926 ty: ClassicalType::BitVec(width),
927 kind: ClassicalExprKind::ExtractBits {
928 value,
929 offset,
930 width,
931 },
932 }),
933 })
934 }
935
936 pub fn concat(parts: impl IntoIterator<Item = Self>) -> Result<Self, CircuitError> {
940 let parts: Vec<Self> = parts.into_iter().collect();
941 if parts.is_empty() {
942 return Err(CircuitError::InvalidOperation(
943 "concat requires at least one part".to_string(),
944 ));
945 }
946
947 let mut total_width = 0u32;
948 for part in &parts {
949 match part.ty() {
950 ClassicalType::Bit => {
951 let Some(next_width) = total_width.checked_add(1) else {
952 return Err(CircuitError::InvalidOperation(
953 "concat width overflows u32".to_string(),
954 ));
955 };
956 total_width = next_width;
957 }
958 ClassicalType::BitVec(width) => {
959 let Some(next_width) = total_width.checked_add(width.get()) else {
960 return Err(CircuitError::InvalidOperation(
961 "concat width overflows u32".to_string(),
962 ));
963 };
964 total_width = next_width;
965 }
966 ty => {
967 return Err(CircuitError::InvalidOperation(format!(
968 "concat expects Bit or BitVec parts, got {ty:?}"
969 )));
970 }
971 }
972 }
973
974 let Some(width) = NonZeroU32::new(total_width) else {
975 return Err(CircuitError::InvalidOperation(
976 "concat width must be non-zero".to_string(),
977 ));
978 };
979 Ok(Self {
980 node: Box::new(ClassicalExprNode {
981 ty: ClassicalType::BitVec(width),
982 kind: ClassicalExprKind::Concat {
983 parts: parts.into_boxed_slice(),
984 },
985 }),
986 })
987 }
988
989 pub fn is_bool_true(&self) -> bool {
991 matches!(self.kind(), ClassicalExprKind::BoolLiteral(true))
992 }
993
994 pub fn is_bool_false(&self) -> bool {
996 matches!(self.kind(), ClassicalExprKind::BoolLiteral(false))
997 }
998
999 pub fn is_bit_true(&self) -> bool {
1001 matches!(self.kind(), ClassicalExprKind::BitLiteral(true))
1002 }
1003
1004 pub fn is_bit_false(&self) -> bool {
1006 matches!(self.kind(), ClassicalExprKind::BitLiteral(false))
1007 }
1008
1009 pub fn simplified(&self) -> Self {
1017 super::simplify::simplify(self)
1018 }
1019
1020 pub(crate) fn from_kind(ty: ClassicalType, kind: ClassicalExprKind) -> Self {
1026 Self {
1027 node: Box::new(ClassicalExprNode { ty, kind }),
1028 }
1029 }
1030
1031 pub fn pack_bits(bits: impl IntoIterator<Item = Self>) -> Result<Self, CircuitError> {
1035 let bits: Vec<Self> = bits.into_iter().collect();
1036 if bits.is_empty() {
1037 return Err(CircuitError::InvalidOperation(
1038 "pack_bits requires at least one bit".to_string(),
1039 ));
1040 }
1041 for bit in &bits {
1042 if bit.ty() != ClassicalType::Bit {
1043 return Err(CircuitError::InvalidOperation(format!(
1044 "pack_bits expects Bit expressions, got {:?}",
1045 bit.ty()
1046 )));
1047 }
1048 }
1049
1050 let Some(width) = NonZeroU32::new(bits.len() as u32) else {
1051 return Err(CircuitError::InvalidOperation(
1052 "pack_bits width must be non-zero".to_string(),
1053 ));
1054 };
1055 Ok(Self {
1056 node: Box::new(ClassicalExprNode {
1057 ty: ClassicalType::BitVec(width),
1058 kind: ClassicalExprKind::PackBits {
1059 bits: bits.into_boxed_slice(),
1060 },
1061 }),
1062 })
1063 }
1064
1065 pub(crate) fn measurement_store_bit(
1071 &self,
1072 target: ClassicalVar,
1073 result: ClassicalValue,
1074 ) -> Option<u32> {
1075 let ClassicalType::BitVec(width) = target.ty() else {
1076 return None;
1077 };
1078 let ClassicalExprKind::PackBits { bits } = self.kind() else {
1079 return None;
1080 };
1081 if bits.len() != width.get() as usize {
1082 return None;
1083 }
1084
1085 let mut measured_index = None;
1086 for (index, bit) in bits.iter().enumerate() {
1087 match bit.kind() {
1088 ClassicalExprKind::Value(value) if *value == result => {
1089 if measured_index.replace(index as u32).is_some() {
1090 return None;
1091 }
1092 }
1093 ClassicalExprKind::ExtractBit {
1094 value,
1095 index: source_index,
1096 } if *source_index == index as u32
1097 && matches!(value.kind(), ClassicalExprKind::Var(var) if *var == target) => {}
1098 _ => return None,
1099 }
1100 }
1101 measured_index
1102 }
1103}
1104
1105impl From<ClassicalVar> for ClassicalExpr {
1106 fn from(var: ClassicalVar) -> Self {
1107 Self::var(var)
1108 }
1109}
1110
1111impl From<ClassicalValue> for ClassicalExpr {
1112 fn from(value: ClassicalValue) -> Self {
1113 Self::value(value)
1114 }
1115}
1116
1117macro_rules! impl_expr_not {
1118 ($ty:ty) => {
1119 impl Not for $ty {
1120 type Output = ClassicalExpr;
1121
1122 fn not(self) -> Self::Output {
1123 ClassicalExpr::try_not(self)
1124 .expect("ClassicalExpr ! operator requires a Bool or Bit expression")
1125 }
1126 }
1127 };
1128}
1129
1130macro_rules! impl_expr_binary_ops {
1131 ($ty:ty) => {
1132 impl<Rhs> BitAnd<Rhs> for $ty
1133 where
1134 Rhs: Into<ClassicalExpr>,
1135 {
1136 type Output = ClassicalExpr;
1137
1138 fn bitand(self, rhs: Rhs) -> Self::Output {
1139 ClassicalExpr::try_and(self, rhs).expect(
1140 "ClassicalExpr & operator requires matching Bool or matching Bit expressions",
1141 )
1142 }
1143 }
1144
1145 impl<Rhs> BitOr<Rhs> for $ty
1146 where
1147 Rhs: Into<ClassicalExpr>,
1148 {
1149 type Output = ClassicalExpr;
1150
1151 fn bitor(self, rhs: Rhs) -> Self::Output {
1152 ClassicalExpr::try_or(self, rhs).expect(
1153 "ClassicalExpr | operator requires matching Bool or matching Bit expressions",
1154 )
1155 }
1156 }
1157
1158 impl<Rhs> BitXor<Rhs> for $ty
1159 where
1160 Rhs: Into<ClassicalExpr>,
1161 {
1162 type Output = ClassicalExpr;
1163
1164 fn bitxor(self, rhs: Rhs) -> Self::Output {
1165 ClassicalExpr::try_xor(self, rhs).expect(
1166 "ClassicalExpr ^ operator requires matching Bool or matching Bit expressions",
1167 )
1168 }
1169 }
1170 };
1171}
1172
1173impl_expr_not!(ClassicalExpr);
1174impl_expr_not!(ClassicalVar);
1175impl_expr_not!(ClassicalValue);
1176impl_expr_binary_ops!(ClassicalExpr);
1177impl_expr_binary_ops!(ClassicalVar);
1178impl_expr_binary_ops!(ClassicalValue);
1179
1180#[cfg(test)]
1181#[path = "expr_test.rs"]
1182mod expr_test;