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