use crate::span::Span;
use crate::syntax::ast::{Child, Node, Wire};
use std::collections::HashSet;
pub fn declared_ids(instances: &[Child]) -> HashSet<String> {
let mut out = HashSet::new();
for c in instances {
collect_ids(c, &mut out);
}
out
}
fn collect_ids(child: &Child, out: &mut HashSet<String>) {
if let Child::Box(n) = child {
if let Some(id) = &n.id {
out.insert(id.clone());
}
for c in &n.children {
collect_ids(c, out);
}
}
}
pub fn auto_created_ids(wires: &[Wire], declared: &HashSet<String>) -> Vec<(String, Span)> {
let mut seen = HashSet::new();
let mut out = Vec::new();
for w in wires {
for group in &w.chain {
for ep in &group.endpoints {
if ep.path.len() != 1 {
continue; }
let id = &ep.path[0];
if declared.contains(id) || !seen.insert(id.clone()) {
continue;
}
out.push((id.clone(), ep.span));
}
}
}
out
}
pub fn auto_box(id: &str, span: Span) -> Node {
Node {
id: Some(id.to_string()),
ty: Some("box".to_string()),
classes: Vec::new(),
style: Vec::new(),
style_span: None,
children: Vec::new(),
wires: Vec::new(),
span,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn parse(src: &str) -> crate::syntax::ast::File {
crate::syntax::parser::parse(&crate::lexer::lex(src).expect("lex")).expect("parse")
}
fn auto_ids(src: &str) -> Vec<String> {
let f = parse(src);
let declared = declared_ids(&f.instances);
auto_created_ids(&f.wires, &declared)
.into_iter()
.map(|(s, _)| s)
.collect()
}
#[test]
fn undeclared_root_wire_ids_are_auto_created() {
assert_eq!(auto_ids("cat -> dog\n"), vec!["cat", "dog"]);
}
#[test]
fn a_declared_id_is_not_auto_created() {
assert_eq!(auto_ids("cat |box|\ncat -> dog\n"), vec!["dog"]);
}
#[test]
fn a_multi_segment_path_never_creates() {
assert_eq!(auto_ids("g |group| [ x |box| ]\ng.x -> y\n"), vec!["y"]);
}
}