Skip to main content

e2rcore/implement/file/
md5common.rs

1use std::io::prelude::*;
2use std::fs::File;
3use std::io::BufReader;
4use std::str;
5use std::iter::Peekable;
6use std::str::Chars;
7use std::collections::HashMap;
8use std::str::FromStr;
9
10#[derive(Debug)]
11#[derive(PartialEq)]
12pub enum Token {
13    Undetermined,
14    Comment,
15    Keyword,
16    Str,
17    Int,
18    Float,
19    Parenl,
20    Parenr,
21    Bracel,
22    Bracer,
23    Invalid,
24    End,
25}
26
27pub fn tokenize < KeywordTok > ( input: &str, idx: usize, hm: & HashMap< &str, KeywordTok > ) -> ( Token, Option< KeywordTok >, usize, usize, usize ) where KeywordTok : Copy {
28    let mut is_float_signed = false;
29    let mut idxcurrent = idx;
30    let mut idxcurrent_start = idx;
31    let mut iter = (&input[ idx.. ]).chars().peekable(); //create peekable iterator
32    {
33        let count_skip = skip_white_space( & mut iter );
34        idxcurrent += count_skip;
35        idxcurrent_start += count_skip;
36    }
37
38    let c = match iter.next() {
39        None => return ( Token::End, None, idxcurrent_start, idxcurrent, idxcurrent ),
40        Some(x) => x
41    };
42    
43    // println!("index:.. {}", idxcurrent );
44    
45    if c == '{' { //process groupings
46        return ( Token::Bracel, None, idxcurrent_start, idxcurrent + 1, idxcurrent + 1 )
47    }else if c == '}' {
48        return ( Token::Bracer, None, idxcurrent_start, idxcurrent + 1, idxcurrent + 1 )
49    }else if c == '(' {
50        return ( Token::Parenl, None, idxcurrent_start, idxcurrent + 1, idxcurrent + 1 )
51    }else if c == ')' {
52        return ( Token::Parenr, None, idxcurrent_start, idxcurrent + 1, idxcurrent + 1 )
53    }else if c == '/' { //process comments
54        let c_2 = match iter.next() {
55            None => return ( Token::Invalid, None, idxcurrent_start, idxcurrent + 1, idxcurrent + 1 ),
56            Some(x) => x
57        };
58        idxcurrent += 1;
59        if c_2 == '/' {
60            while let Some(x) = iter.next() {
61                if x == '\n' {
62                    // println!("new line detected.");
63                    // return ( Token::Comment, None, idxcurrent_start + 2, idxcurrent + 1, idxcurrent + 1 )
64                    //ignore the commnent and tokenize more
65                    return tokenize( input, idxcurrent, hm )
66                }
67                idxcurrent += 1;
68            }
69            //ignore the commnet and tokenize more
70             // return ( Token::Comment, None, idxcurrent_start + 2, idxcurrent, idxcurrent + 1 )
71            return tokenize( input, idxcurrent, hm )
72        }else{
73            return ( Token::Invalid, None, idxcurrent_start, idxcurrent, idxcurrent + 1 )
74        }
75    }
76    else if c == '"' { //process strings
77        idxcurrent += 1;
78        idxcurrent_start += 1;
79        while let Some(x) = iter.next() {
80            if x == '"' {
81                return ( Token::Str, None, idxcurrent_start, idxcurrent, idxcurrent + 1 )
82            }else if !x.is_alphanumeric() && x != '_' && x != '/'{
83                println!("unexpected character in string: {}", x);
84                return ( Token::Invalid, None, idxcurrent_start, idxcurrent, idxcurrent )
85            }
86            idxcurrent += 1;
87        }
88        return ( Token::Invalid, None, idxcurrent_start, idxcurrent, idxcurrent )
89    }
90    else if c.is_alphabetic() || c == '_' { //process keywords and strings
91        idxcurrent += 1;
92        while let Some(x) = iter.next() {
93            if !x.is_alphanumeric() && x != '_' {
94                if let Some(mapped_val) = hm.get( &input[ idxcurrent_start..idxcurrent ] ){
95                    return ( Token::Keyword, Some(*mapped_val), idxcurrent_start, idxcurrent, idxcurrent ) 
96                }else{
97                    return ( Token::Str, None, idxcurrent_start, idxcurrent, idxcurrent )
98                }
99            }
100            idxcurrent += 1;
101        }
102        if let Some(mapped_val) = hm.get( &input[ idxcurrent_start..idxcurrent ] ){
103            return ( Token::Keyword, Some(*mapped_val), idxcurrent_start, idxcurrent, idxcurrent ) 
104        }else{
105            return ( Token::Str, None, idxcurrent_start, idxcurrent, idxcurrent )
106        }
107    }
108
109    if c == '-' || c == '+' { //process optional signedness of a number
110        idxcurrent += 1;
111        is_float_signed = true;
112        let next_c = iter.peek();
113        match next_c { //expect a decimal or digit after
114            None => return ( Token::Invalid, None, idxcurrent_start, idxcurrent, idxcurrent ),
115            Some(x) => {
116                if !x.is_numeric() || *x == '.' {
117                    return ( Token::Invalid, None, idxcurrent_start, idxcurrent, idxcurrent )
118                }
119            }
120        }
121    }
122
123    let c2 = if is_float_signed { //eat a character if the current character is +/-
124        match iter.next() {
125            None => return ( Token::Invalid, None, idxcurrent_start, idxcurrent, idxcurrent ),
126            Some(x) => x
127        }
128    }else{
129        c
130    };
131    
132    if c2 == '.' { //process float
133        idxcurrent += 1;
134        while let Some(x) = iter.next() {
135            if !x.is_numeric() {
136                // println!("number detected.");
137                return ( Token::Float, None, idxcurrent_start, idxcurrent, idxcurrent )
138            }
139            idxcurrent += 1;
140        }
141        return ( Token::Str, None, idxcurrent_start, idxcurrent, idxcurrent )
142    }else if c2.is_numeric() { //process int or float
143        idxcurrent += 1;
144        loop { //process digits
145            {
146                let x = match iter.peek() {
147                    None => return ( Token::Int, None, idxcurrent_start, idxcurrent, idxcurrent ),
148                    Some(x) => x
149                };
150                if !x.is_numeric() {
151                    break;
152                }
153            }
154            iter.next();
155            idxcurrent += 1;
156        }
157        { //process decimal
158            {
159                if *iter.peek().expect("character invalid") != '.' { //int
160                    return ( Token::Int, None, idxcurrent_start, idxcurrent, idxcurrent )
161                }else{
162                    { //consume decimal
163                        idxcurrent += 1; 
164                        iter.next();
165                    }
166                    loop { //digits
167                        if let Some(y) = iter.peek() {
168                            if !y.is_numeric() {
169                                return ( Token::Float, None, idxcurrent_start, idxcurrent, idxcurrent )
170                            }   
171                        } else {
172                            break;
173                        }
174                        iter.next();
175                        idxcurrent += 1;
176                    }
177                    return ( Token::Float, None, idxcurrent_start, idxcurrent, idxcurrent )
178                }
179            }
180        }
181    }
182    //skip unrecognized character
183    ( Token::Undetermined, None, idxcurrent_start, idxcurrent + 1, idxcurrent + 1 )
184}
185
186fn skip_white_space( iter: & mut Peekable<Chars> ) -> usize {
187    let mut skip_count = 0;
188    loop { //skip whitespace
189        let is_white_space = match iter.peek() {
190            Some(x) => {
191                let result = if *x == ' ' || *x == '\n' || *x == '\t' || *x == '\r' {
192                    skip_count += 1;
193                    true
194                }else{
195                    false
196                };
197                result
198            },
199            None => return skip_count
200        };
201        if is_white_space {
202            iter.next();
203        }else{
204            break;
205        }
206    }
207    return skip_count
208}
209
210pub fn file_open( file_path: & str ) -> Option<String> {
211    let path = File::open( file_path ).expect("file path open invalid");
212    let mut buf_reader = BufReader::new(path);
213    let mut contents = String::new();
214    match buf_reader.read_to_string( & mut contents ) {
215        Err( e ) => { println!("{}", e ); return None },
216        _ => (),
217    }
218    Some(contents)
219}
220
221pub fn expect_int_array( input: &str, idx: usize, count: usize, arr: & mut [i64] ) -> Result< usize, & 'static str > {
222    let mut idx_current = idx;
223    let hm : HashMap< &str, bool > = HashMap::new();
224    for i in 0..count {
225        let ( tok, _kw_tok, idx_s, idx_e, idx_next ) = tokenize( input, idx_current, & hm );
226        match tok {
227            Token::Int => {
228                arr[i] = i64::from_str( &input[idx_s..idx_e] ).expect("md5common parse int array invalid");
229                idx_current = idx_next;
230            },
231            _ => return Err("unexpected token. int not found.")
232        }
233    }
234    Ok( idx_current )
235}
236
237pub fn expect_float_array( input: &str, idx: usize, count: usize, arr: & mut [f32] ) -> Result< usize, & 'static str > {
238    let mut idx_current = idx;
239    let hm : HashMap< &str, bool > = HashMap::new();
240    for i in 0..count {
241        let ( tok, _kw_tok, idx_s, idx_e, idx_next ) = tokenize( input, idx_current, & hm );
242        match tok {
243            Token::Float => {
244                arr[i] = f32::from_str( &input[idx_s..idx_e] ).expect("md5common parse int array invalid");
245                idx_current = idx_next;
246            },
247            _ => return Err("unexpected token. float not found.")
248        }
249    }
250    Ok( idx_current )
251}
252
253pub fn expect_parenl( input: &str, idx: usize ) -> Result< usize, & 'static str > {
254    let idx_current = idx;
255    let hm : HashMap< &str, bool > = HashMap::new();
256    let ( tok, _kw_tok, _idx_s, _idx_e, idx_next ) = tokenize( input, idx_current, & hm );
257    match tok {
258        Token::Parenl => return Ok( idx_next ),
259        _ => return Err("unexpected token. parenl not found.")
260    }
261}
262
263pub fn expect_parenr( input: &str, idx: usize ) -> Result< usize, & 'static str > {
264    let idx_current = idx;
265    let hm : HashMap< &str, bool > = HashMap::new();
266    let ( tok, _kw_tok, _idx_s, _idx_e, idx_next ) = tokenize( input, idx_current, & hm );
267    match tok {
268        Token::Parenr => return Ok( idx_next ),
269        _ => return Err("unexpected token. parenr not found.")
270    }
271}
272
273pub fn expect_bracel( input: &str, idx: usize ) -> Result< usize, & 'static str > {
274    let idx_current = idx;
275    let hm : HashMap< &str, bool > = HashMap::new();
276    let ( tok, _kw_tok, _idx_s, _idx_e, idx_next ) = tokenize( input, idx_current, & hm );
277    match tok {
278        Token::Bracel => return Ok( idx_next ),
279        _ => return Err("unexpected token. bracel not found.")
280    }
281}
282
283pub fn expect_bracer( input: &str, idx: usize ) -> Result< usize, & 'static str > {
284    let idx_current = idx;
285    let hm : HashMap< &str, bool > = HashMap::new();
286    let ( tok, _kw_tok, _idx_s, _idx_e, idx_next ) = tokenize( input, idx_current, & hm );
287    match tok {
288        Token::Bracer => return Ok( idx_next ),
289        _ => return Err("unexpected token. bracer not found.")
290    }
291}
292
293pub fn expect_str< KeywordTok >( input: &str, idx: usize, hm: & HashMap< &str, KeywordTok >, ret_str: & mut String ) -> Result< usize, & 'static str > where KeywordTok : Copy {
294    let idx_current = idx;
295    let ( tok, _kw_tok, idx_s, idx_e, idx_next ) = tokenize( input, idx_current, & hm );
296    match tok {
297        Token::Str => {
298            *ret_str = input[idx_s..idx_e].to_string();
299            Ok( idx_next )
300        },
301        _ => { Err("unexpected token. string not found.") }
302    }
303}