Skip to main content

sva_engine/instantiate/
resolved.rs

1// Concern: writes a resolved walk back out, as source text or as a substituted Expr | Non-concern: the walk itself (mod.rs) | IO: (&Expr, Cx) -> String, Expr
2
3use std::collections::BTreeMap;
4
5use sva_ast::{Arg, Expr};
6
7use crate::instantiate::{Bound, Cx, Instances, Node};
8
9impl Instances {
10    pub(crate) fn display_name(&self, file: &str, binds: &[(String, Bound)]) -> String {
11        if binds.is_empty() {
12            return file.to_string();
13        }
14        let args: Vec<String> = binds
15            .iter()
16            .map(|(k, v)| {
17                let v = v.thunk();
18                format!("{k}={}", self.render(v.expr, self.cx(v.scope)))
19            })
20            .collect();
21        format!("{file}({})", args.join(", "))
22    }
23
24    /// The text an instance name and a refusal quote carry, through the one printer.
25    pub fn render(&self, e: &Expr, cx: Cx) -> String {
26        sva_ast::render_expr(&self.copy(e, cx))
27    }
28
29    /// Every instance's body with each parameter already standing for what it was bound to.
30    pub fn exprs(&self) -> BTreeMap<String, Expr> {
31        self.nodes
32            .keys()
33            .map(|path| {
34                let (e, cx) = self.at(path).expect("a key of the map it indexes");
35                (path.clone(), self.copy(e, cx))
36            })
37            .collect()
38    }
39
40    fn copy(&self, e: &Expr, cx: Cx) -> Expr {
41        if let Some(r) = self.follow(e, cx, |e2, cx2| self.copy(e2, cx2)) {
42            return r;
43        }
44        match self.node(e, cx) {
45            Node::Lit(l) => Expr::Lit(l.clone()),
46            Node::Name(name) => Expr::Var(name.to_string()),
47            Node::Bin(op, l, r) => {
48                Expr::Bin(op, Box::new(self.copy(l, cx)), Box::new(self.copy(r, cx)))
49            }
50            Node::Call { name, args, span } => Expr::Call {
51                name: name.to_string(),
52                args: args
53                    .iter()
54                    .map(|a| match a {
55                        Arg::Pos(x) => Arg::Pos(self.copy(x, cx)),
56                        Arg::Named(k, x) => Arg::Named(k.clone(), self.copy(x, cx)),
57                    })
58                    .collect(),
59                span,
60            },
61            Node::Read {
62                path,
63                arg,
64                address,
65                span,
66            } => Expr::Ref {
67                address,
68                path: path.to_string(),
69                arg: Box::new(self.copy(arg, cx)),
70                binds: Vec::new(),
71                span,
72            },
73            Node::Own { arg, address, span } => Expr::SelfRef {
74                arg: Box::new(self.copy(arg, cx)),
75                address,
76                span,
77            },
78            // One node read at its own `t` is that node indexed; any other keeps its name.
79            Node::Signal {
80                name,
81                of,
82                arg,
83                span,
84            } => {
85                let arg = Box::new(self.copy(arg, cx));
86                match self.copy(of.expr, self.signal(of, cx)) {
87                    Expr::Ref {
88                        path,
89                        arg: now,
90                        binds,
91                        address: sva_ast::Address::Time,
92                        ..
93                    } if binds.is_empty() && *now == Expr::Var("t".to_string()) => Expr::Ref {
94                        path,
95                        arg,
96                        binds,
97                        address: sva_ast::Address::Index,
98                        span,
99                    },
100                    _ => Expr::Indexed {
101                        name: name.to_string(),
102                        arg,
103                        span,
104                    },
105                }
106            }
107        }
108    }
109}