use logicaffeine_kernel::Term;
pub fn term_to_verilog(term: &Term) -> String {
let (head, args) = collect_app_chain(term);
if let Term::Global(name) = &head {
match (name.as_str(), args.len()) {
("B0", 0) => return "1'b0".to_string(),
("B1", 0) => return "1'b1".to_string(),
("Tt", 0) => return "/* unit */".to_string(),
("bit_not", 1) => {
let a = term_to_verilog(&args[0]);
return format!("(~{})", a);
}
("bit_and", 2) => {
let a = term_to_verilog(&args[0]);
let b = term_to_verilog(&args[1]);
return format!("({} & {})", a, b);
}
("bit_or", 2) => {
let a = term_to_verilog(&args[0]);
let b = term_to_verilog(&args[1]);
return format!("({} | {})", a, b);
}
("bit_xor", 2) => {
let a = term_to_verilog(&args[0]);
let b = term_to_verilog(&args[1]);
return format!("({} ^ {})", a, b);
}
("bit_mux", 3) => {
let sel = term_to_verilog(&args[0]);
let then_v = term_to_verilog(&args[1]);
let else_v = term_to_verilog(&args[2]);
return format!("({} ? {} : {})", sel, then_v, else_v);
}
("bv_and", 3) => {
let a = term_to_verilog(&args[1]);
let b = term_to_verilog(&args[2]);
return format!("({} & {})", a, b);
}
("bv_or", 3) => {
let a = term_to_verilog(&args[1]);
let b = term_to_verilog(&args[2]);
return format!("({} | {})", a, b);
}
("bv_xor", 3) => {
let a = term_to_verilog(&args[1]);
let b = term_to_verilog(&args[2]);
return format!("({} ^ {})", a, b);
}
("bv_not", 2) => {
let a = term_to_verilog(&args[1]);
return format!("(~{})", a);
}
(fname, _) if !args.is_empty() => {
let arg_strs: Vec<String> = args.iter().map(|a| term_to_verilog(a)).collect();
return format!("{}({})", fname, arg_strs.join(", "));
}
(gname, 0) => return gname.to_string(),
_ => {}
}
}
if let Term::Var(name) = term {
return name.clone();
}
if let Term::Lambda { param, body, .. } = term {
let body_sv = term_to_verilog(body);
return format!("/* λ{} */ {}", param, body_sv);
}
if let Term::Match { discriminant, cases, .. } = term {
if cases.len() == 2 {
let disc = term_to_verilog(discriminant);
let case_b0 = term_to_verilog(&cases[0]);
let case_b1 = term_to_verilog(&cases[1]);
return format!("({} ? {} : {})", disc, case_b1, case_b0);
}
}
if let Term::Lit(lit) = term {
return format!("{}", lit);
}
format!("/* unsupported: {} */", term)
}
fn collect_app_chain(term: &Term) -> (Term, Vec<Term>) {
let mut args = Vec::new();
let mut current = term.clone();
while let Term::App(func, arg) = current {
args.push(*arg);
current = *func;
}
args.reverse();
(current, args)
}