use super::util::node_text;
use sv_parser::RefNode;
pub(crate) fn sv_type_to_veryl(node: &RefNode, src: &str) -> String {
let mut signed = false;
let mut atom: Option<&str> = None;
let mut vector_kind: Option<&str> = None;
let mut packed: Vec<String> = Vec::new();
let mut type_ident: Option<String> = None;
for n in node.clone().into_iter() {
match n {
RefNode::Signing(_) if node_text(&n, src).trim() == "signed" => {
signed = true;
}
RefNode::IntegerAtomType(_) => {
let txt = node_text(&n, src).trim();
atom = Some(match txt {
"byte" => "i8",
"shortint" => "i16",
"int" => "i32",
"longint" => "i64",
"integer" => "i32",
"time" => "u64",
_ => "i32",
});
}
RefNode::IntegerVectorType(_) => {
let txt = node_text(&n, src).trim();
vector_kind = Some(match txt {
"bit" => "bit",
_ => "logic",
});
}
RefNode::PackedDimension(_) => {
packed.push(node_text(&n, src).trim().to_string());
}
RefNode::TypeIdentifier(_) if type_ident.is_none() => {
type_ident = Some(node_text(&n, src).trim().to_string());
}
_ => {}
}
}
if let Some(a) = atom {
return a.to_string();
}
if let Some(t) = type_ident {
return t;
}
let kind = vector_kind.unwrap_or("logic");
let mut s = String::new();
if signed {
s.push_str("signed ");
}
s.push_str(kind);
let widths: Vec<String> = packed
.iter()
.filter_map(|d| packed_dim_to_width(d))
.collect();
if !widths.is_empty() {
s.push('<');
s.push_str(&widths.join(", "));
s.push('>');
}
s
}
pub(crate) fn packed_dim_to_width(dim: &str) -> Option<String> {
let inner = dim.strip_prefix('[')?.strip_suffix(']')?;
let (hi, lo) = inner.split_once(':')?;
let hi = hi.trim();
let lo = lo.trim();
if lo != "0" {
return None;
}
if let Ok(hi_n) = hi.parse::<i64>() {
return Some((hi_n + 1).to_string());
}
if let Some(n) = hi.strip_suffix("-1") {
Some(n.trim().to_string())
} else {
Some(format!("{hi}+1"))
}
}
#[cfg(test)]
mod tests {
use super::packed_dim_to_width;
#[test]
fn numeric_high_minus_one() {
assert_eq!(packed_dim_to_width("[8-1:0]"), Some("8".to_string()));
}
#[test]
fn numeric_high_inclusive() {
assert_eq!(packed_dim_to_width("[7:0]"), Some("8".to_string()));
assert_eq!(packed_dim_to_width("[15:0]"), Some("16".to_string()));
}
#[test]
fn parametric_minus_one() {
assert_eq!(packed_dim_to_width("[N-1:0]"), Some("N".to_string()));
assert_eq!(
packed_dim_to_width("[WIDTH-1:0]"),
Some("WIDTH".to_string())
);
}
#[test]
fn parametric_inclusive() {
assert_eq!(packed_dim_to_width("[N:0]"), Some("N+1".to_string()));
}
#[test]
fn nonzero_low_bound_unsupported() {
assert_eq!(packed_dim_to_width("[7:1]"), None);
assert_eq!(packed_dim_to_width("[N:1]"), None);
}
#[test]
fn malformed_input_returns_none() {
assert_eq!(packed_dim_to_width("[7]"), None);
assert_eq!(packed_dim_to_width("7:0"), None);
assert_eq!(packed_dim_to_width(""), None);
}
}