1use std::sync::atomic::{AtomicU32, Ordering};
4
5use sva_ast::{Address, Arg, BinOp, ByteSpan, Expr, Literal};
6use sva_formula::Hash;
7use sva_samples::Extent;
8
9use crate::typing::{SumSlot, Typing};
10
11pub const NOTES: &str = "notes";
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct Handle(pub u32);
16
17impl Handle {
18 pub(super) fn node(self) -> String {
19 format!("{NOTES}#{}", self.0)
20 }
21}
22
23static HANDLES: AtomicU32 = AtomicU32::new(0);
25
26#[derive(Clone)]
27struct Term {
28 handle: Handle,
29 expr: Expr,
30 addressed: bool,
32 landed: i64,
33}
34
35impl Term {
36 fn holds(&self, handle: Handle) -> bool {
37 self.addressed && self.handle == handle
38 }
39}
40
41#[derive(Clone)]
42enum Slot {
43 Live(Term),
44 Retired(Hash, Extent),
45}
46
47#[derive(Clone, Default)]
48pub(super) struct Terms {
49 slots: Vec<Slot>,
50}
51
52impl Terms {
53 fn live(&self) -> impl Iterator<Item = &Term> {
54 self.slots.iter().filter_map(|s| match s {
55 Slot::Live(t) => Some(t),
56 Slot::Retired(..) => None,
57 })
58 }
59
60 fn live_mut(&mut self) -> impl Iterator<Item = &mut Term> {
61 self.slots.iter_mut().filter_map(|s| match s {
62 Slot::Live(t) => Some(t),
63 Slot::Retired(..) => None,
64 })
65 }
66
67 pub(super) fn count(&self) -> usize {
68 self.live().count()
69 }
70
71 pub(super) fn is_empty(&self) -> bool {
72 self.live().next().is_none()
73 }
74
75 pub(super) fn exprs(&self) -> impl Iterator<Item = &Expr> {
76 self.live().map(|t| &t.expr)
77 }
78
79 pub(super) fn nodes(&self) -> impl Iterator<Item = (String, Expr)> {
80 self.live().map(|t| (t.handle.node(), t.expr.clone()))
81 }
82
83 pub(super) fn handles(&self) -> impl Iterator<Item = Handle> {
84 self.live().map(|t| t.handle)
85 }
86
87 pub(super) fn added(&self, expr: Expr) -> (Terms, Handle) {
88 let mut next = self.clone();
89 let handle = Handle(HANDLES.fetch_add(1, Ordering::Relaxed));
90 next.slots.push(Slot::Live(Term {
91 handle,
92 expr,
93 addressed: true,
94 landed: 0,
95 }));
96 (next, handle)
97 }
98
99 fn held(&mut self, handle: Handle) -> Option<&mut Term> {
100 self.live_mut().find(|t| t.holds(handle))
101 }
102
103 pub(super) fn landed(&self, handle: Handle) -> Option<i64> {
104 Some(self.live().find(|t| t.holds(handle))?.landed)
105 }
106
107 pub(super) fn land(&mut self, handle: Handle, at: i64) {
108 if let Some(term) = self.held(handle) {
109 term.landed = at;
110 }
111 }
112
113 pub(super) fn replaced(&self, handle: Handle, expr: impl FnOnce(i64) -> Expr) -> Option<Terms> {
115 let mut next = self.clone();
116 let term = next.held(handle)?;
117 term.expr = expr(term.landed);
118 Some(next)
119 }
120
121 pub(super) fn removed(&self, handle: Handle, at: f64) -> Option<Terms> {
123 let mut next = self.clone();
124 let term = next.held(handle)?;
125 let never = Expr::Bin(
126 BinOp::Sub,
127 Box::new(Expr::Lit(Literal::Num(0.0))),
128 Box::new(Expr::Var("inf".to_string())),
129 );
130 term.expr = Expr::Call {
131 name: "crop".to_string(),
132 args: vec![
133 Arg::Pos(term.expr.clone()),
134 Arg::Pos(never),
135 Arg::Pos(Expr::Lit(Literal::Num(at))),
136 ],
137 span: SPAN,
138 };
139 term.addressed = false;
140 Some(next)
141 }
142
143 pub(super) fn sum(&self) -> Expr {
144 self.live()
145 .map(|t| Expr::Ref {
146 path: t.handle.node(),
147 arg: Box::new(Expr::Var("t".to_string())),
148 binds: Vec::new(),
149 address: Address::Time,
150 span: SPAN,
151 })
152 .reduce(|sum, t| Expr::Bin(BinOp::Add, Box::new(sum), Box::new(t)))
153 .unwrap_or(Expr::Lit(Literal::Num(0.0)))
154 }
155
156 pub(super) fn name(&self, tys: &mut Typing) {
158 let Some(notes) = tys.id(NOTES) else {
159 return;
160 };
161 let slots = self.slots.iter().map(|s| match s {
162 Slot::Live(t) => tys.id(&t.handle.node()).map(SumSlot::Node),
163 Slot::Retired(h, support) => Some(SumSlot::Retired(*h, *support)),
164 });
165 if let Some(slots) = slots.collect::<Option<Vec<_>>>() {
166 tys.name_sum(notes, slots);
167 }
168 }
169
170 pub(super) fn prune(
173 &mut self,
174 gone: &dyn Fn(Handle) -> bool,
175 named: &dyn Fn(Handle) -> Option<(Hash, Extent)>,
176 ) -> bool {
177 let live = self.live().count();
178 self.slots = std::mem::take(&mut self.slots)
179 .into_iter()
180 .filter_map(|slot| match slot {
181 Slot::Live(t) if gone(t.handle) => {
182 named(t.handle).map(|(identity, support)| Slot::Retired(identity, support))
183 }
184 other => Some(other),
185 })
186 .collect();
187 self.live().count() != live
188 }
189}
190
191const SPAN: ByteSpan = ByteSpan { start: 0, end: 0 };
192
193pub(super) fn placed(expr: &Expr, at: i64) -> Expr {
195 let moved = |e: &Expr| Box::new(placed(e, at));
196 match expr {
197 Expr::Var(name) if name == "t" && at != 0 => Expr::Bin(
198 BinOp::Sub,
199 Box::new(expr.clone()),
200 Box::new(Expr::Lit(Literal::Samples(at as f64))),
201 ),
202 Expr::Lit(_) | Expr::Var(_) => expr.clone(),
203 Expr::Bin(op, l, r) => Expr::Bin(*op, moved(l), moved(r)),
204 Expr::Call { name, args, span } => Expr::Call {
205 name: name.clone(),
206 args: args
207 .iter()
208 .map(|arg| match arg {
209 Arg::Pos(e) => Arg::Pos(placed(e, at)),
210 Arg::Named(n, e) => Arg::Named(n.clone(), placed(e, at)),
211 })
212 .collect(),
213 span: *span,
214 },
215 Expr::Ref {
216 path,
217 arg,
218 binds,
219 address,
220 span,
221 } => Expr::Ref {
222 path: path.clone(),
223 arg: moved(arg),
224 binds: binds
225 .iter()
226 .map(|(n, e)| (n.clone(), placed(e, at)))
227 .collect(),
228 address: *address,
229 span: *span,
230 },
231 Expr::SelfRef { arg, address, span } => Expr::SelfRef {
232 arg: moved(arg),
233 address: *address,
234 span: *span,
235 },
236 Expr::Indexed { name, arg, span } => Expr::Indexed {
237 name: name.clone(),
238 arg: moved(arg),
239 span: *span,
240 },
241 }
242}