1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Types for representing a complete circuit.
use crate::{
diagnostics::{Diagnostic, Validation},
groups::IRGroup,
printer::{IRPrintable, IRPrinter},
traits::{Canonicalize, ConstantFolding, Validatable},
};
/// Generic type representing a circuit.
///
/// Is parametrized on the expression type and the type used to represent the external context
/// relative to the circuit.
#[derive(Debug)]
pub struct IRCircuit<E, C> {
body: Vec<IRGroup<E>>,
context: C,
}
impl<E, C> IRCircuit<E, C> {
/// Creates a new circuit.
pub fn new(body: Vec<IRGroup<E>>, context: C) -> Self {
Self { body, context }
}
/// Returns a reference to the context.
pub fn context(&self) -> &C {
&self.context
}
/// Returns a list of the groups inside the circuit.
pub fn body(&self) -> &[IRGroup<E>] {
&self.body
}
/// Returns a list of mutable references to the groups inside the circuit.
pub fn body_mut(&mut self) -> &mut [IRGroup<E>] {
&mut self.body
}
/// Returns the body of the circuit, consuming it.
pub fn take_body(self) -> Vec<IRGroup<E>> {
self.body
}
/// Returns a printer of the circuit.
pub fn display(&self) -> IRPrinter<'_>
where
Self: IRPrintable,
{
IRPrinter::from(self)
}
/// Returns the main group.
///
/// Panics if there isn't a main group.
pub fn main(&self) -> &IRGroup<E> {
// Reverse the iterator because the main group is likely to be the last one.
self.body
.iter()
.rev()
.find(|g| g.is_main())
.expect("A main group is required")
}
///// Validates the IR, returning errors if it failed.
//pub fn validate(&self) -> (Result<(), ValidationFailed>, Vec<String>) {
// let mut errors = vec![];
//
// for group in &self.body {
// let (status, group_errors) = group.validate(&self.body);
// if status.is_err() {
// for err in group_errors {
// errors.push(format!("Error in group \"{}\": {err}", group.name()));
// }
// }
// }
//
// (
// if errors.is_empty() {
// Ok(())
// } else {
// Err(ValidationFailed {
// name: self
// .body
// .iter()
// .find_map(|g| g.is_main().then_some(g.name()))
// .unwrap_or("circuit")
// .to_string(),
// error_count: errors.len(),
// })
// },
// errors,
// )
//}
}
impl<E, C, D> Validatable for IRCircuit<E, C>
where
IRGroup<E>: Validatable<Diagnostic = D, Context = [IRGroup<E>]>,
D: Diagnostic,
{
type Diagnostic = D;
type Context = ();
fn validate_with_context(
&self,
_: &Self::Context,
) -> Result<Vec<Self::Diagnostic>, Vec<Self::Diagnostic>> {
let mut validation = Validation::new();
for group in &self.body {
let header = format!("in group \"{}\"", group.name());
let result = group.validate_with_context(&self.body);
validation.append_from_result(result, &header);
}
validation.into()
}
}
impl<E, C, Err> ConstantFolding for IRCircuit<E, C>
where
IRGroup<E>: ConstantFolding<Error = Err>,
{
type Error = Err;
type T = ();
fn constant_fold(&mut self) -> Result<(), Self::Error> {
self.body.constant_fold()
}
}
impl<E, C> Canonicalize for IRCircuit<E, C>
where
IRGroup<E>: Canonicalize,
{
fn canonicalize(&mut self) {
self.body.canonicalize()
}
}
impl<E: IRPrintable, C: IRPrintable> IRPrintable for IRCircuit<E, C> {
fn fmt(&self, ctx: &mut crate::printer::IRPrinterCtx<'_, '_>) -> crate::printer::Result {
self.context().fmt(ctx)?;
for group in self.body() {
ctx.nl()?;
group.fmt(ctx)?;
}
Ok(())
}
}