Skip to main content

normalize_languages/
verilog.rs

1//! Verilog/SystemVerilog support.
2
3use crate::{ContainerBody, Import, Language, LanguageSymbols};
4use tree_sitter::Node;
5
6/// Verilog language support.
7pub struct Verilog;
8
9impl Language for Verilog {
10    fn name(&self) -> &'static str {
11        "Verilog"
12    }
13    fn extensions(&self) -> &'static [&'static str] {
14        &["v", "sv", "svh"]
15    }
16    fn grammar_name(&self) -> &'static str {
17        "verilog"
18    }
19
20    fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
21        Some(self)
22    }
23
24    fn extract_imports(&self, node: &Node, content: &str) -> Vec<Import> {
25        if node.kind() != "package_import_declaration" {
26            return Vec::new();
27        }
28
29        let text = &content[node.byte_range()];
30        vec![Import {
31            module: text.trim().to_string(),
32            names: Vec::new(),
33            alias: None,
34            is_wildcard: false,
35            is_relative: false,
36            line: node.start_position().row + 1,
37        }]
38    }
39
40    fn format_import(&self, import: &Import, names: Option<&[&str]>) -> String {
41        // Verilog: import package::*; or import package::item;
42        let names_to_use: Vec<&str> = names
43            .map(|n| n.to_vec())
44            .unwrap_or_else(|| import.names.iter().map(|s| s.as_str()).collect());
45        if names_to_use.is_empty() {
46            format!("import {}::*;", import.module)
47        } else if names_to_use.len() == 1 {
48            format!("import {}::{};", import.module, names_to_use[0])
49        } else {
50            // Multiple items need separate import statements
51            names_to_use
52                .iter()
53                .map(|n| format!("import {}::{};", import.module, n))
54                .collect::<Vec<_>>()
55                .join("\n")
56        }
57    }
58
59    fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
60        // Verilog module_declaration has no dedicated body field; use node itself
61        Some(*node)
62    }
63
64    fn analyze_container_body(
65        &self,
66        body_node: &Node,
67        content: &str,
68        inner_indent: &str,
69    ) -> Option<ContainerBody> {
70        // module foo(...); ... endmodule
71        // Content starts after the port-list semicolon, ends before endmodule.
72        let end = body_node.end_byte();
73        let bytes = content.as_bytes();
74
75        let mut c = body_node.walk();
76        let mut content_start = body_node.start_byte();
77        for child in body_node.children(&mut c) {
78            if child.kind() == ";" {
79                content_start = child.end_byte();
80                if content_start < end && bytes[content_start] == b'\n' {
81                    content_start += 1;
82                }
83                break;
84            }
85        }
86
87        let mut c2 = body_node.walk();
88        let mut content_end = end;
89        for child in body_node.children(&mut c2) {
90            if child.kind() == "endmodule" {
91                content_end = child.start_byte();
92                while content_end > content_start
93                    && matches!(bytes[content_end - 1], b' ' | b'\t' | b'\n')
94                {
95                    content_end -= 1;
96                }
97                break;
98            }
99        }
100
101        let is_empty = content[content_start..content_end].trim().is_empty();
102        Some(ContainerBody {
103            content_start,
104            content_end,
105            inner_indent: inner_indent.to_string(),
106            is_empty,
107        })
108    }
109}
110
111impl LanguageSymbols for Verilog {}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116    use crate::validate_unused_kinds_audit;
117
118    #[test]
119    fn unused_node_kinds_audit() {
120        #[rustfmt::skip]
121        let documented_unused: &[&str] = &[
122            // Declarations
123            "interface_declaration", "checker_declaration",
124            "udp_declaration", "clocking_declaration", "property_declaration",
125            "net_declaration", "data_declaration", "parameter_declaration",
126            "specparam_declaration", "type_declaration", "genvar_declaration",
127            "modport_declaration", "constraint_declaration", "covergroup_declaration",
128            "sequence_declaration", "let_declaration", "local_parameter_declaration",
129            "overload_declaration", "interface_class_declaration", "anonymous_program",
130            "package_declaration",
131            // Module/interface headers
132            "module_ansi_header", "module_nonansi_header",
133            "interface_ansi_header", "interface_nonansi_header",
134            // Items
135            "module_or_generate_item", "interface_or_generate_item", "class_item",
136            "interface_class_item", "checker_or_generate_item_declaration",
137            "tf_item_declaration", "block_item_declaration", "anonymous_program_item",
138            // Identifiers
139            "interface_identifier", "package_identifier",
140            "property_identifier", "checker_identifier",
141            "covergroup_identifier", "cover_point_identifier", "constraint_identifier",
142            "clocking_identifier", "modport_identifier", "generate_block_identifier",
143            "specparam_identifier", "terminal_identifier", "port_identifier",
144            "input_identifier", "output_port_identifier", "index_variable_identifier",
145            "interface_instance_identifier", "hierarchical_btf_identifier",
146            "ps_identifier", "system_tf_identifier",
147            "genvar_identifier",
148            "instance_identifier", "output_identifier", "tf_identifier",
149            "enum_identifier", "member_identifier", "parameter_identifier",
150            "dynamic_array_variable_identifier", "inout_port_identifier",
151            "input_port_identifier", "program_identifier", "cross_identifier",
152            "method_identifier", "formal_port_identifier", "const_identifier",
153            "c_identifier", "escaped_identifier", "text_macro_identifier",
154            // Expressions
155            "expression", "conditional_expression", "inside_expression",
156            "let_expression", "range_expression", "array_range_expression",
157            "case_expression", "expression_or_dist", "data_source_expression",
158            "constant_expression", "constant_mintypmax_expression", "constant_param_expression",
159            "mintypmax_expression", "module_path_expression", "module_path_mintypmax_expression",
160            "clockvar_expression", "inc_or_dec_expression", "assignment_pattern_expression",
161            "event_expression", "param_expression", "select_expression", "bins_expression",
162            "tagged_union_expression", "cycle_delay_const_range_expression",
163            // Statements
164            "statement_or_null", "seq_block", "wait_statement", "jump_statement",
165            "randcase_statement", "action_block", "statement_item", "par_block",
166            "procedural_timing_control_statement", "statement", "disable_statement",
167            "function_statement", "function_statement_or_null",
168            // Assertions
169            "assert_property_statement", "assume_property_statement",
170            "restrict_property_statement", "expect_property_statement",
171            "deferred_immediate_assert_statement", "deferred_immediate_assume_statement",
172            "deferred_immediate_cover_statement", "simple_immediate_assert_statement",
173            "simple_immediate_assume_statement", "simple_immediate_cover_statement",
174            "cover_property_statement", "cover_sequence_statement",
175            "assertion_variable_declaration", "concurrent_assertion_item",
176            "deferred_immediate_assertion_item",
177            // Case
178            "case_item", "case_keyword", "case_pattern_item", "case_inside_item",
179            "case_generate_item", "case_item_expression", "property_case_item",
180            // Generate constructs
181            "loop_generate_construct", "generate_block", "generate_region",
182            "genvar_iteration", "genvar_initialization",
183            // Types
184            "class_type", "integer_vector_type", "struct_union", "struct_union_member",
185            "casting_type", "data_type_or_implicit1", "implicit_data_type1",
186            "integer_atom_type", "type_reference", "net_type", "net_type_declaration",
187            "data_type", "non_integer_type", "data_type_or_void", "enum_base_type",
188            "net_port_type1", "interface_class_type",
189            // Class/method
190            "class_method", "class_property", "class_item_qualifier",
191            "class_constructor_prototype", "method_qualifier", "method_call",
192            "method_call_body", "sequence_method_call", "array_method_name",
193            "class_scope", "class_constructor_declaration", "interface_class_method",
194            "class_qualifier", "class_new", "implicit_class_handle", "random_qualifier",
195            // Functions/tasks
196            "function_prototype", "task_prototype",
197            "tf_port_declaration", "extern_tf_declaration", "function_subroutine_call",
198            "dpi_function_proto", "function_data_type_or_implicit1",
199            "dpi_function_import_property", "dpi_task_proto", "tf_call", "tf_port_list",
200            "tf_port_item1", "tf_port_direction",
201            // Ports
202            "input_declaration", "output_declaration", "inout_declaration",
203            "interface_port_declaration", "interface_port_header", "port_direction",
204            "port_declaration", "list_of_port_declarations", "ansi_port_declaration",
205            // Parameters and lists
206            "parameter_port_declaration", "list_of_tf_variable_identifiers",
207            "list_of_variable_identifiers", "list_of_port_identifiers",
208            "list_of_variable_port_identifiers", "list_of_interface_identifiers",
209            "list_of_type_assignments", "list_of_formal_arguments",
210            "list_of_path_delay_expressions", "identifier_list", "list_of_genvar_identifiers",
211            "list_of_arguments", "list_of_arguments_parent", "list_of_port_connections",
212            "list_of_parameter_assignments", "list_of_clocking_decl_assign",
213            "list_of_cross_items", "list_of_defparam_assignments", "list_of_net_assignments",
214            "list_of_net_decl_assignments", "list_of_param_assignments",
215            "list_of_specparam_assignments", "list_of_udp_port_identifiers",
216            "list_of_variable_assignments", "list_of_variable_decl_assignments",
217            "list_of_path_inputs", "list_of_path_outputs", "variable_identifier_list",
218            // UDP
219            "udp_ansi_declaration", "udp_reg_declaration", "udp_input_declaration",
220            "sequential_entry", "combinational_entry", "combinational_body",
221            "udp_initial_statement", "udp_declaration_port_list", "udp_output_declaration",
222            "udp_nonansi_declaration", "udp_port_declaration", "sequential_body",
223            "udp_port_list", "udp_instance", "udp_instantiation",
224            // Constraints
225            "constraint_expression", "constraint_prototype_qualifier",
226            "extern_constraint_declaration", "solve_before_list", "constraint_block_item",
227            "constraint_block", "constraint_prototype", "constraint_primary",
228            "constraint_set", "uniqueness_constraint", "dist_list", "dist_item", "dist_weight",
229            // Specify
230            "simple_path_declaration", "edge_sensitive_path_declaration",
231            "state_dependent_path_declaration", "specify_input_terminal_descriptor",
232            "specify_output_terminal_descriptor", "showcancelled_declaration",
233            "edge_control_specifier", "edge_identifier", "specify_block",
234            "pulsestyle_declaration", "path_delay_expression", "path_declaration",
235            "parallel_path_description", "full_path_description",
236            "parallel_edge_sensitive_path_description", "full_edge_sensitive_path_description",
237            "path_delay_value",
238            // Operators
239            "stream_operator", "assignment_operator", "operator_assignment",
240            "inc_or_dec_operator", "polarity_operator", "overload_operator",
241            "overload_proto_formals", "unary_operator",
242            // DPI
243            "dpi_import_export", "dpi_task_import_property", "import_export", "dpi_spec_string",
244            // Assignments
245            "nonblocking_assignment", "for_step", "for_variable_declaration",
246            "loop_variables1", "ref_declaration", "blocking_assignment",
247            "for_initialization", "variable_assignment", "net_assignment",
248            "net_decl_assignment", "variable_decl_assignment", "param_assignment",
249            "specparam_assignment", "defparam_assignment", "type_assignment",
250            "assignment_pattern", "assignment_pattern_key",
251            "assignment_pattern_net_lvalue", "assignment_pattern_variable_lvalue",
252            "clocking_decl_assign",
253            // Concatenations
254            "module_path_concatenation", "module_path_multiple_concatenation",
255            "concatenation", "constant_concatenation", "constant_multiple_concatenation",
256            "multiple_concatenation", "streaming_concatenation", "stream_concatenation",
257            "stream_expression", "slice_size", "empty_unpacked_array_concatenation",
258            // Interface/modport
259            "interface_item", "interface_instantiation", "modport_clocking_declaration",
260            "modport_item", "modport_ports_declaration", "modport_simple_ports_declaration",
261            "modport_simple_port", "modport_tf_ports_declaration",
262            // Module instantiation
263            "module_instantiation", "module_keyword", "hierarchical_instance",
264            "name_of_instance", "parameter_value_assignment",
265            "ordered_parameter_assignment", "named_parameter_assignment",
266            "ordered_port_connection", "named_port_connection",
267            "program_instantiation", "checker_instantiation",
268            // Lifetime
269            "lifetime",
270            // Block
271            "block_event_expression", "join_keyword",
272            // Program
273            "program_declaration",
274            // Coverage
275            "cross_body", "cross_body_item", "cover_cross", "cover_point",
276            "coverage_event", "coverage_option", "coverage_spec_or_option",
277            "bins_or_empty", "bins_or_options", "bins_keyword",
278            "bins_selection", "bins_selection_or_option", "select_condition",
279            "covergroup_range_list", "covergroup_value_range",
280            "trans_list", "trans_set", "trans_range_list", "trans_item", "repeat_range",
281            // Cycle delay
282            "cycle_delay", "cycle_delay_range",
283            // Gate types
284            "n_input_gatetype", "n_output_gatetype", "enable_gatetype", "cmos_switchtype",
285            "gate_instantiation", "cmos_switch_instance", "enable_gate_instance",
286            "mos_switch_instance", "n_input_gate_instance", "n_output_gate_instance",
287            "pass_switch_instance", "pass_enable_switch_instance", "pull_gate_instance",
288            "pulldown_strength", "pullup_strength", "enable_terminal", "inout_terminal",
289            "input_terminal", "output_terminal", "ncontrol_terminal", "pcontrol_terminal",
290            // Compiler directives
291            "default_nettype_compiler_directive", "timeunits_declaration",
292            "text_macro_definition",
293            // Clocking
294            "clocking_event", "clocking_item", "clocking_direction",
295            "default_skew", "clocking_skew", "clocking_drive", "clockvar",
296            // Delay/timing
297            "delay3", "delay2", "delay_value", "delay_control", "delay_or_event_control",
298            "event_control", "event_trigger",
299            // Strength
300            "drive_strength", "strength0", "strength1", "charge_strength",
301            // Dimensions
302            "unpacked_dimension", "packed_dimension", "associative_dimension",
303            "queue_dimension", "unsized_dimension",
304            // Selects and ranges
305            "constant_range", "constant_indexed_range", "indexed_range",
306            "constant_primary", "module_path_primary", "primary", "primary_literal",
307            "bit_select1", "select1", "nonrange_select1", "constant_bit_select1",
308            "constant_select1",
309            // Randcase
310            "randcase_item",
311            // Always/initial
312            "always_construct", "always_keyword", "initial_construct", "final_construct",
313            // Continuous assign
314            "continuous_assign", "net_alias", "procedural_continuous_assignment",
315            // Loop
316            "loop_variables1", "open_range_list", "open_value_range",
317            // Pattern
318            "pattern", "cond_pattern", "cond_predicate", "unique_priority",
319            // Enum
320            "enum_name_declaration",
321            // Formal/args
322            "formal_argument", "let_port_list", "let_port_item", "let_list_of_arguments",
323            "let_actual_arg",
324            // Property/sequence
325            "property_port_list", "property_port_item", "property_lvar_port_direction",
326            "property_spec", "property_expr", "sequence_port_list", "sequence_port_item",
327            "sequence_lvar_port_direction", "sequence_expr", "sequence_instance",
328            "sequence_list_of_arguments", "sequence_abbrev",
329            "consecutive_repetition", "non_consecutive_repetition", "goto_repetition",
330            // Lvalues
331            "net_lvalue", "variable_lvalue", "nonrange_variable_lvalue",
332            // Subroutines
333            "subroutine_call", "system_tf_call", "array_manipulation_call", "randomize_call",
334            // Literals
335            "time_literal", "time_unit", "string_literal", "integral_number",
336            "decimal_number", "real_number", "unbased_unsized_literal",
337            // Cast
338            "cast", "dynamic_array_new",
339            // Package
340            "package_export_declaration", "package_scope", "package_import_item",
341            // Attributes
342            "attribute_instance", "attr_spec",
343            // Specparam
344            "pulse_control_specparam", "error_limit_value", "reject_limit_value", "limit_value",
345            // Timing checks
346            "timing_check_event", "timing_check_event_control", "timing_check_condition",
347            "timing_check_limit", "controlled_reference_event", "data_event",
348            "delayed_data", "delayed_reference", "end_edge_offset", "event_based_flag",
349            "reference_event", "remain_active_flag", "timestamp_condition",
350            "start_edge_offset", "threshold", "scalar_timing_check_condition",
351            "scalar_constant", "timecheck_condition", "edge_descriptor",
352            // System timing checks
353            "$setup_timing_check", "$hold_timing_check", "$setuphold_timing_check",
354            "$recovery_timing_check", "$removal_timing_check", "$recrem_timing_check",
355            "$skew_timing_check", "$timeskew_timing_check", "$fullskew_timing_check",
356            "$period_timing_check", "$width_timing_check", "$nochange_timing_check",
357            // Level/edge
358            "level_input_list", "edge_input_list", "edge_indicator", "next_state", "init_val",
359            // Others
360            "pass_switchtype", "pass_en_switchtype", "mos_switchtype",
361            "default_nettype_value",
362            "property_formal_type1", "sequence_formal_type1", "let_formal_type1",
363            "package_or_generate_item_declaration", "notifier",
364            "ps_or_hierarchical_array_identifier", "value_range",
365            // control flow — not extracted as symbols
366            "case_generate_construct",
367            "conditional_statement",
368            "loop_statement",
369            "package_import_declaration",
370            "case_statement",
371            "if_generate_construct",
372        ];
373        validate_unused_kinds_audit(&Verilog, documented_unused)
374            .expect("Verilog unused node kinds audit failed");
375    }
376}