Minimal Imperative Parsing Library | https://docs.rs/mipl

make OrExactMatch take Vec<String> over Vec<&'static str>

ecsolticia.bsky.social d8252bcd 1ef6caf9

verified
Changed files
+117 -33
examples
src
parser
concrete_parser
tests
+96
examples/alphanum.rs
··· 1 + use mipl::prelude::*; 2 + 3 + pub fn alphanum_vec() -> Vec<char> { 4 + let mut vec: Vec<char> = vec![]; 5 + 6 + for i in 65..91 { 7 + vec.push(char::from_u32(i).unwrap()); 8 + } 9 + for i in 97..123 { 10 + vec.push(char::from_u32(i).unwrap()); 11 + } 12 + for i in 48..58 { 13 + vec.push(char::from_u32(i).unwrap()); 14 + } 15 + 16 + vec 17 + } 18 + 19 + pub fn tokenize(src: String) -> Parser { 20 + let alphanum_vec: Vec<char> = alphanum_vec(); 21 + 22 + let del_param = DelimitersParam{ 23 + discard: DiscardDelimiters::new( 24 + vec![ 25 + ' ', 26 + '\n', 27 + '\t' 28 + ] 29 + ), 30 + keep: KeepDelimiters::new( 31 + alphanum_vec 32 + ) 33 + }; 34 + 35 + Parser::from(src, del_param) 36 + } 37 + 38 + fn parse(parser: &mut Parser) -> bool { 39 + let alph_vec: Vec<String> = alphanum_vec() 40 + .into_iter() 41 + .map(|ch| char::to_string(&ch)) 42 + .collect(); 43 + let _collector = CollectWhile::<OrExactMatch>::subparse(alph_vec, parser); 44 + 45 + if let Some(tok) = parser.next() { 46 + match tok { 47 + Token::End(EndToken) => true, 48 + _ => false 49 + } 50 + } else { 51 + true 52 + } 53 + } 54 + 55 + fn main() { 56 + use std::io::Write; 57 + loop { 58 + print!("check if alphanumeric: "); 59 + std::io::stdout().flush().unwrap(); 60 + let input = { 61 + let mut buf = String::new(); 62 + std::io::stdin().read_line(&mut buf).unwrap(); 63 + buf 64 + }; 65 + if input.trim() == "exit" { 66 + break; 67 + } 68 + let mut parser = tokenize(input); 69 + println!("{}", parse(&mut parser)) 70 + } 71 + } 72 + 73 + #[cfg(test)] 74 + mod tests { 75 + use super::*; 76 + 77 + #[test] 78 + fn test_true_alphanum1() { 79 + let input = String::from("helix123"); 80 + let mut parser = tokenize(input); 81 + assert_eq!( 82 + parse(&mut parser), 83 + true 84 + ) 85 + } 86 + 87 + #[test] 88 + fn test_false_alphanum1() { 89 + let input = String::from("13wonder*"); 90 + let mut parser = tokenize(input); 91 + assert_eq!( 92 + parse(&mut parser), 93 + false 94 + ) 95 + } 96 + }
+8 -2
examples/calc.rs
··· 19 19 fn consume_term(parser: &mut Parser) -> Option<f32> { 20 20 let mut num: f32 = consume_fact(parser)?; 21 21 22 - let ops = vec!["*", "/"]; 22 + let ops: Vec<String> = vec!["*", "/"] 23 + .into_iter() 24 + .map(String::from) 25 + .collect(); 23 26 let or_matcher = OrExactMatch::new(ops); 24 27 while let Some(op) = or_matcher.try_next(parser) { 25 28 match op.as_ref() { ··· 35 38 fn consume_expr(parser: &mut Parser) -> Option<f32> { 36 39 let mut term: f32 = consume_term(parser)?; 37 40 38 - let ops = vec!["+", "-"]; 41 + let ops: Vec<String> = vec!["+", "-"] 42 + .into_iter() 43 + .map(String::from) 44 + .collect(); 39 45 let or_matcher = OrExactMatch::new(ops); 40 46 while let Some(op) = or_matcher.try_next(parser) { 41 47 match op.as_ref() {
+3 -5
src/parser/concrete_parser/or_exact_match.rs
··· 22 22 } 23 23 } 24 24 25 - impl IsContainerCpInput for Vec<&'static str> {} 25 + impl IsContainerCpInput for Vec<String> {} 26 26 impl ContainedType for HashSet<String> {} 27 27 28 28 impl ContainerCp for OrExactMatch { 29 29 type ContainedType = HashSet<String>; 30 - type Input = Vec<&'static str>; 30 + type Input = Vec<String>; 31 31 32 32 fn new_contained(value: Self::Input) -> Self::ContainedType { 33 - let final_val = value.iter().cloned().map(String::from); 34 - 35 - HashSet::from_iter(final_val) 33 + HashSet::from_iter(value) 36 34 } 37 35 38 36 fn new(value: Self::Input) -> Self {
+10 -26
tests/test_subparser.rs
··· 226 226 Parser::from(src, del_param) 227 227 } 228 228 229 - #[derive(Debug)] 230 - pub struct Parsers { 231 - /// The parser for expressions 232 - expr_parser: Parser, 233 - /// The parser for initial configuration 234 - states_parser: Parser, 235 - /// The number of steps to take 236 - steps: usize 237 - } 238 - impl Parsers { 239 - pub fn new(parser: &mut Parser) -> Option<Self> { 240 - let states = vec!["*", "#"]; 241 - let expr_parser = CollectUntil::<OrExactMatch>::subparse(states.clone(), parser); 242 - let states_parser = CollectWhile::<OrExactMatch>::subparse(states, parser); 243 - let steps: usize = match parser.next() { 244 - Some(Token::Str(s)) => s.parse().ok(), 245 - _ => None 246 - }?; 229 + fn test_until_doesnt_eat_ending_states_subparser(parser: &mut Parser) -> Parser { 230 + let states: Vec<String> = vec!["*", "#"] 231 + .into_iter() 232 + .map(String::from) 233 + .collect(); 234 + let _expr_parser = CollectUntil::<OrExactMatch>::subparse(states.clone(), parser); 235 + let states_parser = CollectWhile::<OrExactMatch>::subparse(states, parser); 247 236 248 - Some(Parsers { 249 - expr_parser, 250 - states_parser, 251 - steps 252 - }) 253 - } 237 + states_parser 254 238 } 255 239 256 240 #[test] ··· 261 245 262 246 let known_parser_a = tokenize("**#".to_string()); 263 247 264 - let parsers = Parsers::new(&mut flat_parser).unwrap(); 248 + let states_parser = test_until_doesnt_eat_ending_states_subparser(&mut flat_parser); 265 249 266 - assert_parsers_same_till(known_parser_a, parsers.states_parser, 3); 250 + assert_parsers_same_till(known_parser_a, states_parser, 3); 267 251 }