11use std:: fmt:: Write as _;
22use std:: fs:: File ;
3- use std:: io:: { BufRead , BufReader , BufWriter , Write } ;
3+ use std:: io:: { self , BufRead , BufReader , BufWriter , Write } ;
44use std:: path:: PathBuf ;
5+ use std:: process:: { self , Command } ;
56use tiny_keccak:: { Hasher , Sha3 } ;
67
78fn main ( ) {
8- check_lalrpop ( ) ;
9+ check_lalrpop ( "src/python.lalrpop" , "src/python.rs" ) ;
910 gen_phf ( ) ;
1011}
1112
12- fn check_lalrpop ( ) {
13- println ! ( "cargo:rerun-if-changed=src/python.lalrpop" ) ;
14- let sha3_line = BufReader :: with_capacity ( 128 , File :: open ( "src/python.rs" ) . unwrap ( ) )
13+ fn check_lalrpop ( source : & str , generated : & str ) {
14+ println ! ( "cargo:rerun-if-changed={source}" ) ;
15+
16+ let sha_prefix = "// sha3: " ;
17+ let sha3_line = BufReader :: with_capacity ( 128 , File :: open ( generated) . unwrap ( ) )
1518 . lines ( )
16- . nth ( 1 )
17- . unwrap ( )
18- . unwrap ( ) ;
19- let expected_sha3_str = sha3_line. strip_prefix ( "// sha3: " ) . unwrap ( ) ;
19+ . find_map ( |line| {
20+ let line = line. unwrap ( ) ;
21+ line. starts_with ( sha_prefix) . then ( || line)
22+ } )
23+ . expect ( "no sha3 line?" ) ;
24+ let expected_sha3_str = sha3_line. strip_prefix ( sha_prefix) . unwrap ( ) ;
2025
2126 let actual_sha3 = {
2227 let mut hasher = Sha3 :: v256 ( ) ;
23- let mut f = BufReader :: new ( File :: open ( "src/python.lalrpop" ) . unwrap ( ) ) ;
28+ let mut f = BufReader :: new ( File :: open ( source ) . unwrap ( ) ) ;
2429 let mut line = String :: new ( ) ;
2530 while f. read_line ( & mut line) . unwrap ( ) != 0 {
2631 if line. ends_with ( '\n' ) {
@@ -38,24 +43,40 @@ fn check_lalrpop() {
3843 hash
3944 } ;
4045
46+ if sha_equal ( expected_sha3_str, & actual_sha3) {
47+ return ;
48+ }
49+ match Command :: new ( "lalrpop" ) . arg ( source) . status ( ) {
50+ Ok ( stat) if stat. success ( ) => { }
51+ Ok ( stat) => {
52+ eprintln ! ( "failed to execute lalrpop; exited with {stat}" ) ;
53+ process:: exit ( stat. code ( ) . unwrap_or ( 1 ) ) ;
54+ }
55+ Err ( e) if e. kind ( ) == io:: ErrorKind :: NotFound => {
56+ eprintln ! (
57+ "the lalrpop executable is not installed and parser/{source} has been changed"
58+ ) ;
59+ eprintln ! ( "please install lalrpop with `cargo install lalrpop`" ) ;
60+ process:: exit ( 1 ) ;
61+ }
62+ Err ( e) => panic ! ( "io error {e:#}" ) ,
63+ }
64+ }
65+
66+ fn sha_equal ( expected_sha3_str : & str , actual_sha3 : & [ u8 ; 32 ] ) -> bool {
4167 // stupid stupid stupid hack. lalrpop outputs each byte as "{:x}" instead of "{:02x}"
42- let sha3_equal = if expected_sha3_str. len ( ) == 64 {
68+ if expected_sha3_str. len ( ) == 64 {
4369 let mut expected_sha3 = [ 0u8 ; 32 ] ;
4470 for ( i, b) in expected_sha3. iter_mut ( ) . enumerate ( ) {
4571 * b = u8:: from_str_radix ( & expected_sha3_str[ i * 2 ..] [ ..2 ] , 16 ) . unwrap ( ) ;
4672 }
47- actual_sha3 == expected_sha3
73+ * actual_sha3 == expected_sha3
4874 } else {
4975 let mut actual_sha3_str = String :: new ( ) ;
5076 for byte in actual_sha3 {
5177 write ! ( actual_sha3_str, "{byte:x}" ) . unwrap ( ) ;
5278 }
5379 actual_sha3_str == expected_sha3_str
54- } ;
55-
56- if !sha3_equal {
57- eprintln ! ( "you need to recompile lalrpop!" ) ;
58- std:: process:: exit ( 1 ) ;
5980 }
6081}
6182
0 commit comments