Tholp's bespoke website generator
1use core::fmt; 2use std::{ascii::escape_default, error, fmt::Arguments, ops::Index, process::exit, thread::sleep}; 3 4use super::DELIMITERS; 5use crate::types::Token; 6 7pub fn collect_arguments(tokens: &[Token]) -> (Vec<String>, usize) { 8 // Arguments vec and number of tokens consumed 9 //let mut output = Vec::new(); 10 let mut split_tokens = Vec::new(); 11 for tok in tokens { 12 for s in split_keep_delimiters(tok.contents.clone()) { 13 split_tokens.push(s); 14 } 15 } 16 17 let mut quoted: bool = false; 18 let mut entered: bool = false; 19 let mut arg = "".to_string(); 20 let mut args: Vec<String> = Vec::new(); 21 22 let mut in_token_count = 0; 23 24 for tok in split_tokens { 25 in_token_count += 1; // This could be a problem if it something got split above.. 26 if tok.starts_with([' ', '\t']) && !quoted { 27 continue; 28 } 29 30 if !entered && tok.starts_with('(') { 31 entered = true; 32 continue; 33 } 34 35 if !entered { 36 continue; 37 } 38 39 if !quoted && tok.starts_with(')') { 40 break; 41 } 42 43 for c in tok.chars() { 44 if c == '\"' { 45 quoted = !quoted; 46 continue; 47 } 48 49 arg.push(c); 50 } 51 52 if !quoted { 53 args.push(arg.clone()); 54 arg.clear(); 55 } 56 } 57 58 return (args, in_token_count); 59} 60 61pub fn collect_block(tokens: &[Token]) -> Option<(Vec<Token>, usize)> { 62 let mut entered = false; 63 let mut tokens_consumed: usize = 0; 64 let mut entering_bracket_count = 0; 65 let mut exiting_bracket_count = 0; 66 let mut scope_count = 0; //incremented by '{{{', decremented by '}}}' 67 let mut escaped = false; 68 69 let mut block: Vec<Token> = Vec::new(); 70 71 // We dont really care about doing anything that in the block right now 72 // maybe have the Token struct contain scope level later? 73 let mut escaped_tok: Token = Token::new("\\".into(), 0, 0); 74 for tok in tokens { 75 tokens_consumed += 1; 76 if !entered { 77 if tok.contents.is_only_whitespace() { 78 continue; 79 } 80 if tok.contents != "{" 81 // Expected block start, got garbage 82 { 83 // println!("Expected block start, got {}",tok.contents); 84 // for t in &block 85 // { 86 // print!("{} ", t.contents); 87 // } 88 // exit(1); 89 return None; 90 } 91 } 92 93 let mut escaped_used = false; 94 95 // Scope Start 96 if tok.contents == "{" && !escaped { 97 entering_bracket_count += 1; 98 99 if entering_bracket_count == 3 { 100 scope_count += 1; 101 entering_bracket_count = 0; 102 if !entered { 103 entered = true; 104 } 105 } 106 } else { 107 entering_bracket_count = 0; 108 if escaped { 109 escaped_used = true; 110 } 111 } 112 // Scope End 113 if tok.contents == "}" && !escaped { 114 exiting_bracket_count += 1; 115 if exiting_bracket_count == 3 { 116 scope_count -= 1; 117 entering_bracket_count = 0; 118 } 119 if scope_count == 0 { 120 break; 121 } 122 } else { 123 exiting_bracket_count = 0; 124 if escaped { 125 escaped_used = true; 126 } 127 } 128 129 if escaped_used { 130 escaped = false; 131 block.push(escaped_tok.clone()); 132 } 133 134 if tok.contents == "\\" { 135 escaped = true; 136 escaped_tok = tok.clone(); 137 } else { 138 block.push(tok.clone()); 139 } 140 } 141 142 if scope_count != 0 { 143 return None; 144 } 145 146 // if block.len() == 6 147 // // things get ugly if its empty 148 // { 149 // let mut emptyblock = Vec::new(); 150 // emptyblock.push(Token::new( 151 // "".into(), 152 // tokens[0].origin_file, 153 // tokens[0].line_number, 154 // )); 155 // return (emptyblock, tokens_consumed); 156 // } 157 // pop brackets, bad and ugly but idgaf 158 block.drain(..3); 159 block.drain(block.len() - 3..); 160 return Some((block, tokens_consumed)); 161} 162 163// Theres no std function to have the delimiters be their own element in the out vector 164// clean it up a bit here 165pub fn split_keep_delimiters(instr: String) -> Vec<String> { 166 let split: Vec<&str> = instr.split_inclusive(DELIMITERS).collect(); 167 let mut output = Vec::new(); 168 169 for s in split { 170 if s.ends_with(DELIMITERS) { 171 let (token, ending) = s.split_at(s.len() - 1); 172 if token.len() > 0 { 173 output.push(token.to_string()); 174 } 175 output.push(ending.to_string()); 176 //println!("({}, {})", token.to_string(), ending.to_string()) 177 } else { 178 output.push(s.to_string()); 179 } 180 } 181 return output; 182} 183 184pub fn strings_to_tokens(in_strings: Vec<String>, origin_file: usize) -> Vec<Token> { 185 let mut tokens = Vec::new(); 186 let mut line_count = 1; 187 188 for str in in_strings { 189 if str.len() == 0 { 190 continue; 191 } 192 193 let current_line = line_count; 194 for char in str.chars() { 195 if char == '\n' { 196 line_count += 1; 197 } 198 } 199 let token: Token = Token::new(str, origin_file, current_line); 200 tokens.push(token); 201 } 202 203 return tokens; 204} 205 206// Need to do some special case stuff so you can macros without spaces between 207// (something like "stuff!insert(..)" is split to ["stuff","!insert(..)"] so it can be acted on later) 208pub fn split_to_tokens(instr: String, origin_file: usize) -> Vec<Token> { 209 let split = split_keep_delimiters(instr); 210 let mut new_split: Vec<String> = Vec::new(); 211 for s in split { 212 let prefix_offset = s.find(&['!', '&']); 213 if prefix_offset.is_some() { 214 let (first, second) = s.split_at(prefix_offset.unwrap()); 215 //println!("\"{}\", \"{}\"", first, second); 216 if first.len() > 0 { 217 new_split.push(first.to_string()); 218 } 219 if second.len() > 0 { 220 new_split.push(second.to_string()); 221 } 222 } else { 223 if s.len() > 0 { 224 new_split.push(s); 225 } 226 } 227 //sleep(std::time::Duration::from_millis(10)); 228 } 229 return strings_to_tokens(new_split, origin_file); 230} 231 232pub fn next_nonwhitespace_token(tokens: &Vec<Token>, index: usize) -> (bool, usize) { 233 while index < tokens.len() { 234 if tokens[index].contents.is_only_whitespace() { 235 continue; 236 } 237 return (true, index); 238 } 239 return (false, 0); 240} 241 242//trim whitespace from the ends 243pub fn trim_whitespace_tokens(tokens: &[Token]) -> &[Token] { 244 let mut start: usize = 0; 245 let mut end: usize = tokens.len(); 246 for tok in tokens { 247 if !tok.contents.is_only_whitespace() { 248 break; 249 } 250 start = start + 1; 251 } 252 253 for tok in tokens.iter().rev() { 254 if !tok.contents.is_only_whitespace() { 255 break; 256 } 257 end = end - 1; 258 } 259 260 return &tokens[start..end]; 261} 262 263pub fn find_pattern(tokens: &[Token], pat: String) -> Option<(usize, usize)> { 264 // (startpoint, length) 265 let split_pattern = split_to_tokens(pat, 0); 266 let mut pattern_index: usize = 0; 267 let mut token_index: usize = 0; 268 let mut working_pattern_index: usize = 0; 269 270 for t in tokens { 271 if t.contents == split_pattern[pattern_index].contents { 272 pattern_index += 1; 273 } else { 274 pattern_index = 0; 275 working_pattern_index = token_index + 1; 276 } 277 278 if pattern_index == split_pattern.len() { 279 return Some((working_pattern_index, split_pattern.len())); 280 } 281 282 token_index += 1; 283 } 284 285 None 286} 287 288pub trait WhitespaceChecks { 289 fn is_only_whitespace(&self) -> bool; 290 fn contains_whitespace(&self) -> bool; 291} 292 293impl WhitespaceChecks for String { 294 fn is_only_whitespace(&self) -> bool { 295 for c in self.chars() { 296 if !c.is_whitespace() { 297 return false; 298 } 299 } 300 return true; 301 } 302 303 fn contains_whitespace(&self) -> bool { 304 for c in self.chars() { 305 if c.is_whitespace() { 306 return true; 307 } 308 } 309 return false; 310 } 311}