55// Copyright (c) 2018, Olof Kraigher olof.kraigher@gmail.com
66
77use clap:: Parser ;
8+ use itertools:: Itertools ;
89use std:: path:: Path ;
9- use std:: time:: SystemTime ;
10- use vhdl_lang:: { Config , Diagnostic , MessagePrinter , NullMessages , Project , Severity , SeverityMap } ;
10+ use vhdl_lang:: { Config , Diagnostic , MessagePrinter , Project , Severity , SeverityMap } ;
1111
1212/// Run vhdl analysis
1313#[ derive( Parser , Debug ) ]
1414#[ command( author, version, about, long_about = None ) ]
1515struct Args {
16- /// The number of threads to use. By default the maximum is selected based on process cores
16+ /// The number of threads to use. By default, the maximum is selected based on process cores
1717 #[ arg( short = 'p' , long) ]
1818 num_threads : Option < usize > ,
1919
20- /// Prints the number of files processed and the execution time
21- #[ arg( long, default_value_t = false ) ]
22- perf : bool ,
23-
24- /// Run repeatedly to get a reliable benchmark result
25- #[ arg( long, default_value_t = false ) ]
26- bench : bool ,
27-
28- /// Hide hint diagnostics
29- #[ arg( long, default_value_t = false ) ]
30- no_hint : bool ,
20+ /// Path to the config file for the VHDL standard libraries (i.e., IEEE std_logic_1164).
21+ /// If omitted, will search for these libraries in a set of standard paths
22+ #[ arg( short = 'l' , long) ]
23+ libraries : Option < String > ,
3124
3225 /// Config file in TOML format containing libraries and settings
3326 #[ arg( short, long) ]
3427 config : String ,
35-
36- /// Dump items that are not resolved into an unique reference
37- /// This is used for development to test where the language server is blind
38- #[ arg( long) ]
39- dump_unresolved : bool ,
40-
41- /// Count items that are not resolved into an unique reference
42- /// This is used for development to test where the language server is blind
43- #[ arg( long) ]
44- count_unresolved : bool ,
4528}
4629
4730fn main ( ) {
@@ -53,77 +36,36 @@ fn main() {
5336
5437 let mut config = Config :: default ( ) ;
5538 let mut msg_printer = MessagePrinter :: default ( ) ;
56- config. load_external_config ( & mut msg_printer) ;
39+ config. load_external_config ( & mut msg_printer, args . libraries . clone ( ) ) ;
5740 config. append (
5841 & Config :: read_file_path ( Path :: new ( & args. config ) ) . expect ( "Failed to read config file" ) ,
5942 & mut msg_printer,
6043 ) ;
6144
62- let start = SystemTime :: now ( ) ;
63-
64- let iterations = if args. bench {
65- let iterations = 10 ;
66- println ! ( "Running {iterations} iterations for benchmarking" ) ;
67- for _ in 0 ..( iterations - 1 ) {
68- let mut project = Project :: from_config ( config. clone ( ) , & mut NullMessages ) ;
69- project. analyse ( ) ;
70- }
71- iterations
72- } else {
73- 1
74- } ;
75-
7645 let severity_map = * config. severities ( ) ;
7746 let mut project = Project :: from_config ( config, & mut msg_printer) ;
78- let mut diagnostics = project. analyse ( ) ;
79- let duration = start. elapsed ( ) . unwrap ( ) / iterations;
80-
81- if args. no_hint {
82- diagnostics. retain ( |diag| severity_map[ diag. code ] != Some ( Severity :: Hint ) ) ;
83- }
47+ project. enable_unused_declaration_detection ( ) ;
48+ let diagnostics = project. analyse ( ) ;
8449
8550 show_diagnostics ( & diagnostics, & severity_map) ;
8651
87- if args. perf || args. bench {
88- let mut num_files = 0 ;
89- let mut num_lines = 0 ;
90- for source_file in project. files ( ) {
91- num_files += 1 ;
92- num_lines += source_file. num_lines ( ) ;
93- }
94- let duration_per_line = duration. checked_div ( num_lines as u32 ) . unwrap ( ) ;
95-
96- println ! ( "Analyzed {num_files} files with {num_lines} lines of code" ) ;
97- println ! (
98- "Total time to run was {} ms with an average of {} ns per line" ,
99- duration. as_millis( ) ,
100- duration_per_line. as_nanos( )
101- ) ;
102- }
103-
104- if args. dump_unresolved || args. count_unresolved {
105- let ( total, unresolved) = project. find_all_unresolved ( ) ;
106-
107- if args. dump_unresolved {
108- for pos in unresolved. iter ( ) {
109- println ! ( "{}" , pos. show( "Unresolved" ) ) ;
110- }
111- }
112-
113- if args. count_unresolved {
114- println ! ( "{} out of {} positions unresolved" , unresolved. len( ) , total) ;
115- }
52+ if diagnostics
53+ . iter ( )
54+ . any ( |diag| severity_map[ diag. code ] . is_some_and ( |severity| severity == Severity :: Error ) )
55+ {
56+ std:: process:: exit ( 1 ) ;
57+ } else {
58+ std:: process:: exit ( 0 ) ;
11659 }
117-
118- // Exit without running Drop on entire allocated AST
119- std:: process:: exit ( 0 ) ;
12060}
12161
12262fn show_diagnostics ( diagnostics : & [ Diagnostic ] , severity_map : & SeverityMap ) {
123- for diagnostic in diagnostics {
124- if let Some ( str) = diagnostic. show ( severity_map) {
125- println ! ( "{str}" ) ;
126- }
63+ let diagnostics = diagnostics
64+ . iter ( )
65+ . filter_map ( |diag| diag. show ( severity_map) )
66+ . collect_vec ( ) ;
67+ for str in & diagnostics {
68+ println ! ( "{str}" ) ;
12769 }
12870
12971 if !diagnostics. is_empty ( ) {
0 commit comments