1use std::collections::BTreeMap;
4
5use sva_ast::{Arg, Expr};
6
7use crate::instantiate::{Bound, Cx, Instances, Node};
8
9#[derive(Debug, PartialEq)]
11pub(crate) struct Resolution {
12 file: String,
13 body: Expr,
14 binds: Vec<(String, Expr)>,
15 reads: Vec<String>,
16}
17
18impl Instances {
19 pub(crate) fn resolution(&self, path: &str) -> Option<Resolution> {
20 let held = self.nodes.get(path)?;
21 let (body, cx) = self.at(path)?;
22 let binds = self.vars(held.body.scope).map(|(name, bound)| {
23 let cx = self.cx(bound.scope);
24 (name.to_string(), self.copy(bound.expr, cx))
25 });
26 Some(Resolution {
27 file: held.file.clone(),
28 body: self.copy(body, cx),
29 binds: binds.collect(),
30 reads: self.deps(path).to_vec(),
31 })
32 }
33
34 pub(crate) fn display_name(&self, file: &str, binds: &[(String, Bound)]) -> String {
35 if binds.is_empty() {
36 return file.to_string();
37 }
38 let args: Vec<String> = binds
39 .iter()
40 .map(|(k, v)| {
41 let v = v.thunk();
42 format!("{k}={}", self.render(v.expr, self.cx(v.scope)))
43 })
44 .collect();
45 format!("{file}({})", args.join(", "))
46 }
47
48 pub fn render(&self, e: &Expr, cx: Cx) -> String {
50 sva_ast::render_expr(&self.copy(e, cx))
51 }
52
53 pub fn exprs(&self) -> BTreeMap<String, Expr> {
55 self.nodes
56 .keys()
57 .map(|path| {
58 let (e, cx) = self.at(path).expect("a key of the map it indexes");
59 (path.clone(), self.copy(e, cx))
60 })
61 .collect()
62 }
63
64 fn copy(&self, e: &Expr, cx: Cx) -> Expr {
65 if let Some(r) = self.follow(e, cx, |e2, cx2| self.copy(e2, cx2)) {
66 return r;
67 }
68 match self.node(e, cx) {
69 Node::Lit(l) => Expr::Lit(l.clone()),
70 Node::Name(name) => Expr::Var(name.to_string()),
71 Node::Bin(op, l, r) => {
72 Expr::Bin(op, Box::new(self.copy(l, cx)), Box::new(self.copy(r, cx)))
73 }
74 Node::Call { name, args, span } => Expr::Call {
75 name: name.to_string(),
76 args: args
77 .iter()
78 .map(|a| match a {
79 Arg::Pos(x) => Arg::Pos(self.copy(x, cx)),
80 Arg::Named(k, x) => Arg::Named(k.clone(), self.copy(x, cx)),
81 })
82 .collect(),
83 span,
84 },
85 Node::Read {
86 path,
87 arg,
88 address,
89 span,
90 } => Expr::Ref {
91 address,
92 path: path.to_string(),
93 arg: Box::new(self.copy(arg, cx)),
94 binds: Vec::new(),
95 span,
96 },
97 Node::Own { arg, address, span } => Expr::SelfRef {
98 arg: Box::new(self.copy(arg, cx)),
99 address,
100 span,
101 },
102 Node::Signal {
104 name,
105 of,
106 arg,
107 span,
108 } => {
109 let arg = Box::new(self.copy(arg, cx));
110 match self.copy(of.expr, self.signal(of, cx)) {
111 Expr::Ref {
112 path,
113 arg: now,
114 binds,
115 address: sva_ast::Address::Time,
116 ..
117 } if binds.is_empty() && *now == Expr::Var("t".to_string()) => Expr::Ref {
118 path,
119 arg,
120 binds,
121 address: sva_ast::Address::Index,
122 span,
123 },
124 _ => Expr::Indexed {
125 name: name.to_string(),
126 arg,
127 span,
128 },
129 }
130 }
131 }
132 }
133}