Implement groundwork for challenge 13.
This commit is contained in:
65
src/parser.rs
Normal file
65
src/parser.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Token {
|
||||
Identifier(String),
|
||||
Equal,
|
||||
Ampersand,
|
||||
}
|
||||
|
||||
pub type Tokens = Vec<Token>;
|
||||
|
||||
pub fn parse_key_value(text: &str) -> HashMap<String, String> {
|
||||
/* Parses foo=bar&baz=qux&zap=zazzle into respective hashmap. */
|
||||
let mut tokens: Tokens = vec![];
|
||||
let mut result = HashMap::new();
|
||||
tokens = scan(text, 0, tokens);
|
||||
for token_chunk in tokens.chunks(4) {
|
||||
match &token_chunk[..] {
|
||||
[Token::Identifier(key), Token::Equal, Token::Identifier(value), Token::Ampersand] => {
|
||||
result.insert(key.to_string(), value.to_string());
|
||||
}
|
||||
[Token::Identifier(key), Token::Equal, Token::Identifier(value)] => {
|
||||
result.insert(key.to_string(), value.to_string());
|
||||
}
|
||||
_ => panic!("Could not parse {:?}", token_chunk),
|
||||
};
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn scan(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens {
|
||||
if ix == code.len() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
let c: char = code[ix..ix + 1].chars().next().unwrap();
|
||||
if c.is_ascii_alphanumeric() || SPECIAL_CHARS.contains(&c) {
|
||||
return scan_identifier(code, ix, tokens);
|
||||
} else if c == '&' {
|
||||
tokens.push(Token::Ampersand);
|
||||
} else if c == '=' {
|
||||
tokens.push(Token::Equal);
|
||||
} else {
|
||||
panic!("Unexpected char '{}' at index {}", c, ix);
|
||||
}
|
||||
ix += 1;
|
||||
scan(code, ix, tokens)
|
||||
}
|
||||
|
||||
fn scan_identifier(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens {
|
||||
let start_ix = ix;
|
||||
let mut chars = code[ix..].chars();
|
||||
while let Some(c) = chars.next() {
|
||||
if c.is_ascii_alphanumeric() || SPECIAL_CHARS.contains(&c) {
|
||||
ix += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let token = Token::Identifier(code[start_ix..ix].to_string());
|
||||
tokens.push(token);
|
||||
scan(code, ix, tokens)
|
||||
}
|
||||
|
||||
const SPECIAL_CHARS: &[char] = &['.', '@'];
|
||||
Reference in New Issue
Block a user