Skip to main content

sva_cli/
trace.rs

1// Concern: seeds a trace from every entry point and names what the caller asked for | Non-concern: the traversal itself (sva-engine), JSON shape (output.rs) | IO: (dir, target) -> Traced or CliError
2
3use std::path::Path;
4
5use sva_ast::{Expr, Graph, Literal};
6use sva_core::{CliError, PROBE, define_probe_for, prepared, refuse_unresolved_bars};
7use sva_engine::{EngineError, Traced};
8
9use crate::lint::{entry_points, referenced};
10
11pub struct Traceable {
12    pub bpm: Option<f64>,
13    pub meter: Option<String>,
14    pub traced: Traced,
15}
16
17/// Every entry point is a root: `master` has no privilege, an uninstantiated bench refuses.
18pub fn trace(dir: &Path, target: &str) -> Result<Traceable, CliError> {
19    let mut graph = prepared(&sva_ast::Dir::at(dir))?;
20    refuse_unresolved_bars(&graph)?;
21
22    let mut roots = entry_points(&graph);
23    if graph.defines(target)
24        && !roots.iter().any(|r| r == target)
25        && !referenced(&graph).contains(target)
26    {
27        roots.push(target.to_string());
28    }
29    let traced = match sva_engine::trace(&graph, &roots, target) {
30        Err(EngineError::UnknownNode(ref name)) if name == target && !graph.defines(target) => {
31            probe(&mut graph, target)?
32        }
33        other => other.map_err(CliError::Engine)?,
34    };
35    Ok(Traceable {
36        bpm: number(graph.global("bpm")),
37        meter: text(graph.global("meter")),
38        traced,
39    })
40}
41
42/// `text` is neither node nor instance: argv math, an entry point of its own.
43fn probe(graph: &mut Graph, text: &str) -> Result<Traced, CliError> {
44    define_probe_for(graph, text)?;
45    let roots = entry_points(graph);
46    sva_engine::trace(graph, &roots, PROBE).map_err(CliError::Engine)
47}
48
49fn number(e: Option<&Expr>) -> Option<f64> {
50    match e {
51        Some(Expr::Lit(Literal::Num(v))) => Some(*v),
52        _ => None,
53    }
54}
55
56fn text(e: Option<&Expr>) -> Option<String> {
57    match e {
58        Some(Expr::Lit(Literal::Str(v))) => Some(v.clone()),
59        _ => None,
60    }
61}