extract_rust_hdl_interface/extract_verilog_interface/
get_constant_number.rs

1use sv_parser::{unwrap_node, RefNode, SyntaxTree};
2
3pub fn get_constant_number(node: RefNode, ast: &SyntaxTree) -> Option<i64> {
4    // unwrap_node! can take multiple types
5    let value = match unwrap_node!(node, IntegralNumber, RealNumber) {
6        Some(RefNode::IntegralNumber(x)) => {
7            match unwrap_node!(x, DecimalNumber, OctalNumber, BinaryNumber, HexNumber) {
8                Some(RefNode::DecimalNumber(x)) => {
9                    let RefNode::UnsignedNumber(unsigned_number) =
10                        unwrap_node!(x, UnsignedNumber).unwrap() else {
11                        panic!("No UnsignedNumber found");
12                        };
13                    let locate = unsigned_number.nodes.0;
14                    let unsigned_value = ast.get_str(&locate).unwrap();
15                    Some(i64::from_str_radix(unsigned_value, 10).unwrap())
16                }
17                Some(RefNode::OctalNumber(octal_number)) => {
18                    let octal_value_node = &octal_number.nodes.2;
19                    let locate = octal_value_node.nodes.0;
20                    let octal_value = ast.get_str(&locate).unwrap();
21                    Some(i64::from_str_radix(octal_value, 8).unwrap())
22                }
23                Some(RefNode::BinaryNumber(binary_number)) => {
24                    let binary_value_node = &binary_number.nodes.2;
25                    let locate = binary_value_node.nodes.0;
26                    let binary_value = ast.get_str(&locate).unwrap();
27                    Some(i64::from_str_radix(binary_value, 2).unwrap())
28                }
29                Some(RefNode::HexNumber(hex_number)) => {
30                    let hex_value_node = &hex_number.nodes.2;
31                    let locate = hex_value_node.nodes.0;
32                    let hex_value = ast.get_str(&locate).unwrap();
33                    Some(i64::from_str_radix(hex_value, 16).unwrap())
34                }
35                _ => panic!("Should not happen"),
36            }
37        }
38
39        Some(RefNode::RealNumber(_x)) => {
40            panic!("RealNumber not supported yet")
41        }
42        _ => None,
43    };
44    value
45}
46
47#[cfg(test)]
48mod tests {
49    use crate::verilog_parser::parse_verilog_string;
50
51    use super::*;
52
53    #[test]
54    fn should_return_first_number_constant() {
55        let result =
56            parse_verilog_string("module counter(input clock, output [5:0] led); endmodule");
57        let syntax_tree = result.unwrap();
58        let number =
59            get_constant_number(syntax_tree.into_iter().next().unwrap(), &syntax_tree).unwrap();
60        assert_eq!(number, 5);
61    }
62
63    #[test]
64    fn works_with_hex_numbers() {
65        let result = parse_verilog_string("reg a = 64'h0F;");
66        let syntax_tree = result.unwrap();
67        let number =
68            get_constant_number(syntax_tree.into_iter().next().unwrap(), &syntax_tree).unwrap();
69        assert_eq!(number, 0xf);
70    }
71
72    #[test]
73    fn works_with_octal_numbers() {
74        let result = parse_verilog_string("reg a = 64'o07;");
75        let syntax_tree = result.unwrap();
76        let number =
77            get_constant_number(syntax_tree.into_iter().next().unwrap(), &syntax_tree).unwrap();
78        assert_eq!(number, 7);
79    }
80
81    #[test]
82    fn works_with_binary_numbers() {
83        let result = parse_verilog_string("reg a = 64'b11010;");
84        let syntax_tree = result.unwrap();
85        let number =
86            get_constant_number(syntax_tree.into_iter().next().unwrap(), &syntax_tree).unwrap();
87        assert_eq!(number, 0b11010);
88    }
89
90    #[test]
91    fn works_without_number() {
92        let result = parse_verilog_string("reg a;");
93        let syntax_tree = result.unwrap();
94        let number = get_constant_number(syntax_tree.into_iter().next().unwrap(), &syntax_tree);
95        assert_eq!(number, None);
96    }
97}