Skip to main content

sva_engine/instantiate/
resolved.rs

1// Concern: writes a resolved walk back out, as source text, a substituted Expr or what an instance is typed from | 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
9/// What an instance is typed from, each parameter standing for what it was bound to.
10#[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    /// The text an instance name and a refusal quote carry, through the one printer.
49    pub fn render(&self, e: &Expr, cx: Cx) -> String {
50        sva_ast::render_expr(&self.copy(e, cx))
51    }
52
53    /// Every instance's body with each parameter already standing for what it was bound to.
54    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            // One node read at its own `t` is that node indexed; any other keeps its name.
103            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}