1mod build;
4mod edges;
5mod resolved;
6
7use std::collections::{BTreeMap, BTreeSet, HashMap};
8use std::sync::Arc;
9
10use sva_ast::{Address, Arg, BinOp, ByteSpan, Defined, Expr, Literal};
11
12use crate::error::EngineError;
13use crate::time::Grid;
14use sva_ast::is_builtin;
15
16use build::Journal;
17pub use build::{from_roots, instantiate};
18use edges::Edges;
19
20pub(crate) type ScopeId = u32;
21
22pub(crate) const NO_PARAMS: ScopeId = 0;
24
25#[derive(Clone, Copy, Debug)]
26pub struct Thunk<'a> {
27 pub(crate) expr: &'a Expr,
28 pub(crate) scope: ScopeId,
29}
30
31#[derive(Clone, Debug)]
33pub(crate) struct Written {
34 defined: Arc<Defined>,
35 path: Arc<[u32]>,
36}
37
38impl Written {
39 pub(crate) fn of(defined: &Arc<Defined>, line: u32) -> Written {
41 Written {
42 defined: Arc::clone(defined),
43 path: [line].into(),
44 }
45 }
46
47 pub(crate) fn expr(&self) -> &Expr {
48 let (line, path) = self.path.split_first().expect("a line");
49 let top = match *line {
50 0 => &self.defined.body,
51 k => &self.defined.defaults[k as usize - 1].1,
52 };
53 let mut at = top;
54 for k in path {
55 at = child(at, *k).expect("a path down this expression");
56 }
57 at
58 }
59}
60
61#[derive(Clone, Copy)]
63pub(crate) enum Child {
64 First,
65 Right,
66 Arg(u32),
67 Bind(u32),
68}
69
70impl Child {
71 pub(crate) fn index(self) -> u32 {
72 match self {
73 Child::First => 0,
74 Child::Right => 1,
75 Child::Arg(k) => k,
76 Child::Bind(k) => k + 1,
77 }
78 }
79}
80
81fn child(e: &Expr, k: u32) -> Option<&Expr> {
82 let k = k as usize;
83 match e {
84 Expr::Bin(_, l, r) => [l, r].get(k).map(|c| &***c),
85 Expr::Call { args, .. } => args.get(k).map(|(Arg::Pos(x) | Arg::Named(_, x))| x),
86 Expr::Ref { arg, binds, .. } => match k {
87 0 => Some(arg),
88 k => binds.get(k - 1).map(|(_, x)| x),
89 },
90 Expr::SelfRef { arg, .. } | Expr::Indexed { arg, .. } => (k == 0).then_some(&**arg),
91 Expr::Lit(_) | Expr::Var(_) => None,
92 }
93}
94
95#[derive(Clone, Debug)]
96pub(crate) struct Bound {
97 pub(crate) written: Written,
98 pub(crate) scope: ScopeId,
99}
100
101impl Bound {
102 pub(crate) fn thunk(&self) -> Thunk<'_> {
103 Thunk {
104 expr: self.written.expr(),
105 scope: self.scope,
106 }
107 }
108}
109
110#[derive(Debug)]
112pub(crate) struct Scope {
113 pub(crate) vars: Vec<(String, Bound)>,
114 keys: Vec<u64>,
115 seen: u64,
116 chained: bool,
117 held: u32,
118 sites: HashMap<usize, String>,
120}
121
122#[derive(Debug)]
124pub(crate) struct Instance {
125 pub(crate) body: Bound,
126 pub(crate) file: String,
127 given: Vec<String>,
128 site: (String, Option<ByteSpan>),
129 held: u32,
130 scanned: bool,
131}
132
133#[inline]
135pub(crate) fn packed(name: &str) -> u64 {
136 let bytes = name.as_bytes();
137 let mut key = (bytes.len() as u64) << 56;
138 for (at, byte) in bytes.iter().take(7).enumerate() {
139 key |= u64::from(*byte) << (at * 8);
140 }
141 key
142}
143
144#[inline]
145fn bit(key: u64) -> u64 {
146 1u64 << ((key ^ (key >> 32)) & 63)
147}
148
149impl Scope {
150 pub(crate) fn new(vars: Vec<(String, Bound)>, chained: bool) -> Scope {
151 let keys: Vec<u64> = vars.iter().map(|(k, _)| packed(k)).collect();
152 let seen = keys.iter().fold(0, |acc, k| acc | bit(*k));
153 Scope {
154 vars,
155 keys,
156 seen,
157 chained,
158 held: 0,
159 sites: HashMap::new(),
160 }
161 }
162
163 #[inline]
166 pub(crate) fn get(&self, name: &str, key: u64) -> Option<&Bound> {
167 if self.seen & bit(key) == 0 {
168 return None;
169 }
170 self.keys
171 .iter()
172 .enumerate()
173 .find(|(at, k)| **k == key && (name.len() <= 7 || self.vars[*at].0 == name))
174 .map(|(at, _)| &self.vars[at].1)
175 }
176}
177
178#[derive(Clone, Copy)]
181pub struct Cx<'a> {
182 pub(crate) scope: ScopeId,
183 pub(crate) time: Option<&'a Time<'a>>,
184 pub(crate) grid: Grid,
185}
186
187pub(crate) struct Time<'a> {
188 pub(crate) expr: &'a Expr,
189 pub(crate) cx: Cx<'a>,
190}
191
192enum Move<'a> {
193 Here(&'a Expr, Cx<'a>),
194 Shifted(&'a Expr, ScopeId, &'a Expr),
195}
196
197impl<'a> Cx<'a> {
198 pub(crate) fn under(self, scope: ScopeId) -> Cx<'a> {
199 Cx { scope, ..self }
200 }
201
202 pub(crate) fn on(self, grid: Grid) -> Cx<'a> {
203 Cx { grid, ..self }
204 }
205}
206
207pub fn resolve_ref_path(referencing: &str, ref_path: &str) -> Result<String, EngineError> {
209 sva_ast::resolve_ref_path(referencing, ref_path)
210 .ok_or_else(|| EngineError::RefAboveRoot(referencing.to_string(), ref_path.to_string()))
211}
212
213pub const SIGNAL_PARAM: &str = "x";
216
217pub const MAX_INSTANCES: usize = 4096;
219
220#[derive(Clone, Copy)]
222pub enum Node<'a> {
223 Lit(&'a Literal),
224 Name(&'a str),
225 Bin(BinOp, &'a Expr, &'a Expr),
226 Call {
227 name: &'a str,
228 args: &'a [Arg],
229 span: ByteSpan,
230 },
231 Read {
232 path: &'a str,
233 arg: &'a Expr,
234 address: Address,
235 span: ByteSpan,
236 },
237 Own {
238 arg: &'a Expr,
239 address: Address,
240 span: ByteSpan,
241 },
242 Signal {
244 name: &'a str,
245 of: Thunk<'a>,
246 arg: &'a Expr,
247 span: ByteSpan,
248 },
249}
250
251#[derive(Debug)]
254pub struct Instances {
255 pub(crate) scopes: Vec<Option<Scope>>,
256 free: Vec<ScopeId>,
257 nodes: BTreeMap<String, Instance>,
258 edges: Edges,
259 pub(crate) own_terms: BTreeMap<String, String>,
260 files: BTreeMap<String, BTreeSet<String>>,
261 journal: Journal,
262 pub(crate) time: Expr,
263 pub(crate) rate: u32,
265}
266
267impl Instances {
268 pub fn new(rate: u32) -> Instances {
269 Instances {
270 scopes: vec![Some(Scope::new(Vec::new(), false))],
271 free: Vec::new(),
272 nodes: BTreeMap::new(),
273 edges: Edges::default(),
274 own_terms: BTreeMap::new(),
275 files: BTreeMap::new(),
276 journal: Journal::default(),
277 time: Expr::Var("t".to_string()),
278 rate,
279 }
280 }
281
282 pub(crate) fn rate(&self) -> u32 {
283 self.rate
284 }
285
286 pub(crate) fn grid(&self) -> Grid {
287 Grid::of(self.rate)
288 }
289
290 pub(crate) fn cx(&self, scope: ScopeId) -> Cx<'_> {
291 Cx {
292 scope,
293 time: None,
294 grid: self.grid(),
295 }
296 }
297
298 pub fn origin(&self, instance: &str) -> Option<&str> {
299 self.nodes.get(instance).map(|held| held.file.as_str())
300 }
301
302 pub fn deps(&self, path: &str) -> &[String] {
303 self.edges.of(path)
304 }
305
306 pub(crate) fn readers(&self, path: &str) -> impl Iterator<Item = &str> {
307 self.edges.readers(path)
308 }
309
310 fn insert(&mut self, name: String, held: Instance) {
312 let files = self.files.entry(held.file.clone()).or_default();
313 files.insert(name.clone());
314 self.nodes.insert(name, held);
315 }
316
317 fn remove(&mut self, name: &str) -> (Instance, Vec<String>) {
319 let held = self.nodes.remove(name).expect("an instance held");
320 let files = self
321 .files
322 .get_mut(&held.file)
323 .expect("its file's instances");
324 files.remove(name);
325 if files.is_empty() {
326 self.files.remove(&held.file);
327 }
328 (held, self.edges.cleared(name))
329 }
330
331 pub(crate) fn scope(&self, id: ScopeId) -> &Scope {
332 self.scopes[id as usize]
333 .as_ref()
334 .expect("a scope something holds")
335 }
336
337 pub fn paths(&self) -> impl Iterator<Item = &str> {
338 self.nodes.keys().map(String::as_str)
339 }
340
341 pub fn holds(&self, path: &str) -> bool {
342 self.nodes.contains_key(path)
343 }
344
345 pub fn instance_of(&self, target: &str) -> Result<String, EngineError> {
348 if self.holds(target) {
349 return Ok(target.to_string());
350 }
351 if let Some(own) = self.own_terms.get(target) {
352 return Ok(own.clone());
353 }
354 sole(
355 target,
356 self.instances_of(target).map(|p| (p.clone(), p)).collect(),
357 )
358 }
359
360 pub fn instances_of<'a>(&'a self, file: &'a str) -> impl Iterator<Item = String> + 'a {
361 let held = self.files.get(file).into_iter().flatten();
362 held.map(String::clone)
363 }
364
365 pub fn at<'a>(&'a self, path: &str) -> Option<(&'a Expr, Cx<'a>)> {
366 let thunk = self.nodes.get(path)?.body.thunk();
367 Some((thunk.expr, self.cx(thunk.scope)))
368 }
369
370 pub fn bindings<'a>(&'a self, path: &str) -> Option<Vec<(&'a str, &'a Expr, Cx<'a>)>> {
371 let scope = self.nodes.get(path)?.body.scope;
372 Some(
373 self.vars(scope)
374 .map(|(name, value)| (name, value.expr, self.cx(value.scope)))
375 .collect(),
376 )
377 }
378
379 pub(crate) fn vars(&self, scope: ScopeId) -> impl Iterator<Item = (&str, Thunk<'_>)> {
381 let vars = self.scope(scope).vars.iter();
382 vars.map(|(name, bound)| (name.as_str(), bound.thunk()))
383 }
384
385 pub(crate) fn bound_names(&self) -> impl Iterator<Item = &str> {
387 let vars = self
388 .scopes
389 .iter()
390 .flatten()
391 .flat_map(|scope| scope.vars.iter());
392 vars.map(|(name, _)| name.as_str())
393 }
394}
395
396pub(crate) fn sole<T>(target: &str, mut held: Vec<(String, T)>) -> Result<T, EngineError> {
399 match held.len() {
400 0 => Err(EngineError::UnknownNode(target.to_string())),
401 1 => Ok(held.remove(0).1),
402 _ => Err(EngineError::AmbiguousNode(
403 target.to_string(),
404 held.into_iter().map(|(name, _)| name).collect(),
405 )),
406 }
407}
408
409fn implicit_time(name: &str) -> bool {
410 sva_ast::FINITE_DIFFERENCE.contains(&name)
411 || sva_ast::MODAL.contains(&name)
412 || matches!(name, "noise" | "stft" | "istft")
413}
414
415impl Instances {
416 #[inline]
417 pub(crate) fn binds(&self, scope: ScopeId, name: &str) -> Option<Thunk<'_>> {
418 let bound = self.scope(scope).get(name, packed(name))?;
419 Some(bound.thunk())
420 }
421
422 #[inline]
424 pub fn follow<'a, R>(
425 &'a self,
426 e: &'a Expr,
427 cx: Cx<'a>,
428 go: impl FnOnce(&'a Expr, Cx<'_>) -> R,
429 ) -> Option<R> {
430 match self.step(e, cx)? {
431 Move::Here(e2, cx2) => Some(go(e2, cx2)),
432 Move::Shifted(e2, scope, when) => {
433 let moved = Time { expr: when, cx };
434 Some(go(
435 e2,
436 Cx {
437 scope,
438 time: Some(&moved),
439 grid: cx.grid,
440 },
441 ))
442 }
443 }
444 }
445
446 #[inline(always)]
448 fn step<'a>(&'a self, e: &'a Expr, cx: Cx<'a>) -> Option<Move<'a>> {
449 match e {
450 Expr::Var(name) if name == "t" => cx.time.map(|t| Move::Here(t.expr, t.cx)),
451 Expr::Var(name) => self
452 .binds(cx.scope, name)
453 .map(|b| Move::Here(b.expr, cx.under(b.scope))),
454 Expr::Call { name, args, .. } => {
455 let bound = self.binds(cx.scope, name)?;
456 let [Arg::Pos(when)] = args.as_slice() else {
457 return None;
458 };
459 Some(Move::Shifted(bound.expr, bound.scope, when))
460 }
461 _ => None,
462 }
463 }
464
465 #[inline]
466 pub fn node<'a>(&'a self, e: &'a Expr, cx: Cx<'_>) -> Node<'a> {
467 match e {
468 Expr::Lit(l) => Node::Lit(l),
469 Expr::Var(name) => Node::Name(name),
470 Expr::Bin(op, l, r) => Node::Bin(*op, l, r),
471 Expr::SelfRef { arg, address, span } => Node::Own {
472 arg,
473 address: *address,
474 span: *span,
475 },
476 Expr::Ref {
477 path,
478 arg,
479 address,
480 span,
481 ..
482 } => Node::Read {
483 path: self.site(e, cx.scope, path),
484 arg,
485 address: *address,
486 span: *span,
487 },
488 Expr::Indexed { name, arg, span } => match self.binds(cx.scope, name) {
489 Some(of) => Node::Signal {
490 name,
491 of,
492 arg,
493 span: *span,
494 },
495 None => Node::Name(name),
496 },
497 Expr::Call { name, args, span } if is_builtin(name) => Node::Call {
498 name,
499 args,
500 span: *span,
501 },
502 Expr::Call { name, span, .. } => Node::Read {
503 path: self.site(e, cx.scope, name),
504 arg: &self.time,
505 address: Address::Time,
506 span: *span,
507 },
508 }
509 }
510
511 fn site<'a>(&'a self, e: &Expr, scope: ScopeId, written: &'a str) -> &'a str {
512 match self
513 .scope(scope)
514 .sites
515 .get(&(std::ptr::from_ref(e) as usize))
516 {
517 Some(child) => child,
518 None => written,
519 }
520 }
521
522 pub(crate) fn signal<'a>(&self, of: Thunk<'a>, cx: Cx<'a>) -> Cx<'a> {
524 Cx {
525 scope: of.scope,
526 time: None,
527 grid: cx.grid,
528 }
529 }
530
531 pub(crate) fn is_now(&self, e: &Expr, cx: Cx) -> bool {
532 if let Some(r) = self.follow(e, cx, |e2, cx2| self.is_now(e2, cx2)) {
533 return r;
534 }
535 matches!(self.node(e, cx), Node::Name(n) if n == "t")
536 }
537
538 fn direct_deps(&self, path: &str) -> Vec<String> {
540 let (e, cx) = self.at(path).expect("an instance");
541 let mut out = Vec::new();
542 self.direct_refs(e, cx, &mut out);
543 out.sort();
544 out.dedup();
545 out
546 }
547
548 fn direct_refs(&self, e: &Expr, cx: Cx, out: &mut Vec<String>) {
549 if self
550 .follow(e, cx, |e2, cx2| self.direct_refs(e2, cx2, out))
551 .is_some()
552 {
553 return;
554 }
555 match self.node(e, cx) {
556 Node::Lit(_) | Node::Name(_) => {}
557 Node::Bin(_, l, r) => {
558 self.direct_refs(l, cx, out);
559 self.direct_refs(r, cx, out);
560 }
561 Node::Call { args, .. } => {
562 for a in args {
563 let (Arg::Pos(x) | Arg::Named(_, x)) = a;
564 self.direct_refs(x, cx, out);
565 }
566 }
567 Node::Read { path, arg, .. } => {
568 out.push(path.to_string());
569 self.direct_refs(arg, cx, out);
570 }
571 Node::Own { arg, .. } => self.direct_refs(arg, cx, out),
572 Node::Signal { of, arg, .. } => {
573 self.direct_refs(of.expr, self.signal(of, cx), out);
574 self.direct_refs(arg, cx, out);
575 }
576 }
577 }
578
579 pub fn reads_self(&self, path: &str) -> bool {
580 self.at(path).is_some_and(|(e, cx)| self.holds_self(e, cx))
581 }
582
583 pub(crate) fn holds_self(&self, e: &Expr, cx: Cx) -> bool {
584 if let Some(r) = self.follow(e, cx, |e2, cx2| self.holds_self(e2, cx2)) {
585 return r;
586 }
587 match self.node(e, cx) {
588 Node::Lit(_) | Node::Name(_) => false,
589 Node::Own { .. } => true,
590 Node::Bin(_, l, r) => self.holds_self(l, cx) || self.holds_self(r, cx),
591 Node::Read { arg, .. } | Node::Signal { arg, .. } => self.holds_self(arg, cx),
592 Node::Call { args, .. } => args.iter().any(|a| {
593 let (Arg::Pos(x) | Arg::Named(_, x)) = a;
594 self.holds_self(x, cx)
595 }),
596 }
597 }
598
599 pub(crate) fn position_dependent(&self, e: &Expr, cx: Cx) -> Option<String> {
601 if let Some(r) = self.follow(e, cx, |e2, cx2| self.position_dependent(e2, cx2)) {
602 return r;
603 }
604 match self.node(e, cx) {
605 Node::Lit(_) | Node::Name(_) => None,
606 Node::Own { .. } => Some("self".to_string()),
607 Node::Bin(_, l, r) => self
608 .position_dependent(l, cx)
609 .or_else(|| self.position_dependent(r, cx)),
610 Node::Read { arg, .. } | Node::Signal { arg, .. } => self.position_dependent(arg, cx),
611 Node::Call { name, args, .. } => {
612 if crate::vocabulary::shape(name).is_some() || name == "crop" || implicit_time(name)
613 {
614 return Some(name.to_string());
615 }
616 args.iter().find_map(|a| {
617 let (Arg::Pos(x) | Arg::Named(_, x)) = a;
618 self.position_dependent(x, cx)
619 })
620 }
621 }
622 }
623
624 pub(crate) fn same<'x, 'y>(&self, a: &Expr, ax: Cx<'x>, b: &Expr, by: Cx<'y>) -> bool {
626 if let Some(moved) = self.step(a, ax) {
627 return match moved {
628 Move::Here(a2, ax2) => self.same(a2, ax2, b, by),
629 Move::Shifted(a2, scope, when) => {
630 let moved = Time { expr: when, cx: ax };
631 self.same(
632 a2,
633 Cx {
634 scope,
635 time: Some(&moved),
636 grid: ax.grid,
637 },
638 b,
639 by,
640 )
641 }
642 };
643 }
644 if let Some(moved) = self.step(b, by) {
645 return match moved {
646 Move::Here(b2, by2) => self.same(a, ax, b2, by2),
647 Move::Shifted(b2, scope, when) => {
648 let moved = Time { expr: when, cx: by };
649 self.same(
650 a,
651 ax,
652 b2,
653 Cx {
654 scope,
655 time: Some(&moved),
656 grid: by.grid,
657 },
658 )
659 }
660 };
661 }
662 match (self.node(a, ax), self.node(b, by)) {
663 (Node::Lit(x), Node::Lit(y)) => x == y,
664 (Node::Name(x), Node::Name(y)) => x == y,
665 (Node::Bin(o1, l1, r1), Node::Bin(o2, l2, r2)) => {
666 o1 == o2 && self.same(l1, ax, l2, by) && self.same(r1, ax, r2, by)
667 }
668 (
669 Node::Own {
670 arg: x, address: i, ..
671 },
672 Node::Own {
673 arg: y, address: j, ..
674 },
675 ) => i == j && self.same(x, ax, y, by),
676 (
677 Node::Read {
678 path: p,
679 arg: x,
680 address: i,
681 ..
682 },
683 Node::Read {
684 path: q,
685 arg: y,
686 address: j,
687 ..
688 },
689 ) => p == q && i == j && self.same(x, ax, y, by),
690 (Node::Signal { of: f, arg: x, .. }, Node::Signal { of: g, arg: y, .. }) => {
691 self.same(f.expr, self.signal(f, ax), g.expr, self.signal(g, by))
692 && self.same(x, ax, y, by)
693 }
694 (
695 Node::Call {
696 name: n1, args: a1, ..
697 },
698 Node::Call {
699 name: n2, args: a2, ..
700 },
701 ) => {
702 n1 == n2
703 && a1.len() == a2.len()
704 && a1.iter().zip(a2).all(|(x, y)| match (x, y) {
705 (Arg::Pos(x), Arg::Pos(y)) => self.same(x, ax, y, by),
706 (Arg::Named(k1, x), Arg::Named(k2, y)) => {
707 k1 == k2 && self.same(x, ax, y, by)
708 }
709 _ => false,
710 })
711 }
712 _ => false,
713 }
714 }
715
716 pub(crate) fn same_binds(&self, scope: ScopeId, binds: &[(String, Bound)]) -> bool {
717 let held = &self.scope(scope).vars;
718 held.len() == binds.len()
719 && held.iter().zip(binds).all(|((k1, v1), (k2, v2))| {
720 let (v1, v2) = (v1.thunk(), v2.thunk());
721 k1 == k2 && self.same(v1.expr, self.cx(v1.scope), v2.expr, self.cx(v2.scope))
722 })
723 }
724}