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