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

add collect_if_sequence subparsers

ecsolticia.codeberg.page a1f6b2ed 3fa68c98

verified
+244 -6
+7
src/lexer.rs
··· 59 59 self.0.push_back(token) 60 60 } 61 61 62 + /// Get [Tokens] from a vector of [Token] items. 63 + pub fn from_vec(toks: Vec<Token>) -> Tokens { 64 + Tokens( 65 + VecDeque::from(toks) 66 + ) 67 + } 68 + 62 69 /// Get a new empty list of tokens. 63 70 pub fn new_empty() -> Tokens { 64 71 Tokens(VecDeque::new())
+25 -1
src/parser.rs
··· 14 14 self.tokens.peek().cloned() 15 15 } 16 16 17 + /// Extend the parser with [Tokens]. 18 + /// 19 + /// Current implementation *could be* 20 + /// costly as it relies on cloning. 21 + pub fn extend(&mut self, tokens: Tokens) { 22 + let mut toks_buf = Tokens::new_empty(); 23 + 24 + for token in self.clone() { 25 + toks_buf.add_token(token); 26 + } 27 + 28 + for token in tokens.clone() { 29 + toks_buf.add_token(token); 30 + } 31 + 32 + self.tokens = tokens.peekable(); 33 + } 34 + 35 + /// Get a new empty [Parser]. 36 + pub fn new_empty() -> Parser { 37 + let tokens = Tokens::new_empty(); 38 + Self::new(tokens) 39 + } 40 + 17 41 /// Create a new [Parser] from tokens. 18 42 pub fn new(tokens: Tokens) -> Parser { 19 43 Parser { tokens: tokens.peekable() } ··· 39 63 } 40 64 41 65 pub mod concrete_parser; 42 - pub mod subparser; 66 + pub mod subparser;
+13 -1
src/parser/subparser.rs
··· 16 16 C: concrete_parser::ContainerCp; 17 17 } 18 18 19 + /// Functionality to build blanket [Parsers](Parser) using 20 + /// a parent [Parser] by consuming a list of tokens from it. 21 + pub trait VariadicConcreteSubparser<C> { 22 + /// Build the subparser based on the concrete parser. 23 + fn subparse 24 + (values: Vec<C::Input>, parser: &mut Parser) -> Parser 25 + where 26 + C: concrete_parser::ContainerCp; 27 + } 28 + 19 29 mod collect_till; 20 30 mod collect_while; 31 + mod collect_if_sequence; 21 32 pub use { 22 33 collect_till::CollectTill, 23 34 collect_while::CollectWhile, 24 - }; 35 + collect_if_sequence::{CollectIfSeq, CollectIfExactSeq}, 36 + };
+67
src/parser/subparser/collect_if_sequence.rs
··· 1 + use crate::prelude::*; 2 + 3 + /// Consume a sequence of tokens into a new parser while the 4 + /// concrete parsers return something. Stop consuming once 5 + /// all values are exhausted, or if one of then returned 6 + /// `None`. 7 + pub struct CollectIfSeq<Cp: ConcreteParser>(Cp); 8 + impl<Cp> VariadicConcreteSubparser<Cp> for CollectIfSeq<Cp> 9 + where 10 + Cp: ConcreteParser 11 + { 12 + fn subparse 13 + (values: Vec<Cp::Input>, parser: &mut Parser) -> Parser 14 + where 15 + Cp: concrete_parser::ContainerCp 16 + { 17 + let mut tokens = Tokens::new_empty(); 18 + 19 + for v in values { 20 + let cp = Cp::new(v); 21 + 22 + if let Some(token) = cp.try_next_token(parser) { 23 + tokens.add_token(token); 24 + } 25 + } 26 + 27 + Parser::new(tokens) 28 + } 29 + } 30 + 31 + /// Consume a sequence of tokens into a new parser **if** 32 + /// the coming sequence of tokens match a sequence. 33 + pub struct CollectIfExactSeq<Cp: ConcreteParser>(Cp); 34 + impl<Cp> VariadicConcreteSubparser<Cp> for CollectIfExactSeq<Cp> 35 + where 36 + Cp: ConcreteParser 37 + { 38 + fn subparse 39 + (values: Vec<Cp::Input>, parser: &mut Parser) -> Parser 40 + where 41 + Cp: concrete_parser::ContainerCp 42 + { 43 + let mut toks_buffer: Tokens = Tokens::new_empty(); 44 + 45 + let mut exact: bool = true; 46 + 47 + for v in values { 48 + let cp = Cp::new(v); 49 + 50 + if let Some(token) = cp.try_next_token(parser) { 51 + toks_buffer.add_token(token) 52 + } else { 53 + if let Some(token) = parser.next() { 54 + toks_buffer.add_token(token); 55 + } 56 + exact = false; 57 + } 58 + } 59 + 60 + if exact { 61 + Parser::new(toks_buffer) 62 + } else { 63 + parser.extend(toks_buffer); 64 + Parser::new_empty() 65 + } 66 + } 67 + }
+1 -4
src/parser/subparser/collect_while.rs
··· 3 3 /// Consume tokens into a new parser while the concrete 4 4 /// parser returns something. Stop consuming if it returns 5 5 /// `None`. 6 - /// 7 - /// Said concrete pattern here is provided by 8 - /// the generic parameter `Op`. 9 6 pub struct CollectWhile<Op: ConcreteParser>(Op); 10 7 impl<Op> ConcreteSubparser<Op> for CollectWhile<Op> 11 8 where ··· 30 27 31 28 Parser::new(tokens) 32 29 } 33 - } 30 + }
+131
tests/test_subparser.rs
··· 3 3 mod common; 4 4 use common::*; 5 5 6 + /// Assert that two parsers successively yield a certain number 7 + /// `n` of the same token. 8 + fn assert_parsers_same_till( 9 + mut a: Parser, 10 + mut b: Parser, 11 + n: usize 12 + ) { 13 + let mut i: usize = 0; 14 + while i < n { 15 + assert_eq!(a.next(), b.next()); 16 + i += 1; 17 + } 18 + } 19 + 20 + fn not_assert_parsers_same_till( 21 + mut a: Parser, 22 + mut b: Parser, 23 + n: usize 24 + ) { 25 + let mut i: usize = 0; 26 + let mut not: bool = false; 27 + while i < n { 28 + if a.next() != b.next() { 29 + not = true; 30 + break; 31 + } 32 + i += i; 33 + } 34 + assert!(not) 35 + } 36 + 6 37 #[test] 7 38 fn test_collect_till_exact_match_subparser() { 8 39 let mut parser = setup_space_seps_parser( ··· 64 95 assert_eq!(known_subparser.next(), subparser.next()); 65 96 i += 1; 66 97 } 98 + } 99 + 100 + #[test] 101 + fn test_collect_if_sequence() { 102 + let mut parser = setup_space_seps_parser( 103 + "a b c d e f g h i j" 104 + ); 105 + let known_subparser = setup_space_seps_parser( 106 + "a b c d" 107 + ); 108 + 109 + let values: Vec<String> = vec!["a", "b", "c", "d", "e"] 110 + .into_iter() 111 + .map(String::from) 112 + .collect(); 113 + 114 + let subparser = CollectIfSeq::<ExactMatch>::subparse( 115 + values, 116 + &mut parser 117 + ); 118 + 119 + assert_parsers_same_till( 120 + known_subparser, 121 + subparser, 122 + 4 123 + ); 124 + } 125 + 126 + #[test] 127 + fn test_collect_if_exact_sequence() { 128 + let mut parser = setup_space_seps_parser( 129 + "a b c d e f g h i j" 130 + ); 131 + let known_subparser = setup_space_seps_parser( 132 + "a b" 133 + ); 134 + 135 + let values: Vec<String> = vec!["a", "b", "c", "d"] 136 + .into_iter() 137 + .map(String::from) 138 + .collect(); 139 + 140 + let subparser = CollectIfExactSeq::<ExactMatch>::subparse( 141 + values, 142 + &mut parser 143 + ); 144 + 145 + assert_parsers_same_till( 146 + known_subparser, 147 + subparser, 148 + 2 149 + ); 150 + } 151 + 152 + #[test] 153 + fn test_fail_collect_if_exact_sequence() { 154 + let mut parser = setup_space_seps_parser( 155 + "a b c d e f g h i j" 156 + ); 157 + let known_subparser = setup_space_seps_parser( 158 + "a b c d" 159 + ); 160 + 161 + let values: Vec<String> = vec!["a", "b", "c", "d", "f"] 162 + .into_iter() 163 + .map(String::from) 164 + .collect(); 165 + 166 + let subparser = CollectIfExactSeq::<ExactMatch>::subparse( 167 + values, 168 + &mut parser 169 + ); 170 + 171 + not_assert_parsers_same_till( 172 + known_subparser, 173 + subparser, 174 + 4 175 + ); 176 + } 177 + 178 + #[test] 179 + fn test_fail_collect_if_exact_keeps_parent_parser_intact() { 180 + let mut parser = setup_space_seps_parser( 181 + "a b c d" 182 + ); 183 + let initial_parser = parser.clone(); 184 + 185 + let values: Vec<String> = vec!["a", "b", "c", "e"] 186 + .into_iter() 187 + .map(String::from) 188 + .collect(); 189 + 190 + let _subparser = CollectIfExactSeq::<ExactMatch>::subparse( 191 + values, 192 + &mut parser 193 + ); 194 + 195 + println!("{:#?}", parser); 196 + 197 + assert_parsers_same_till(parser, initial_parser, 4); 67 198 }