use lazy_static::lazy_static;
use regex::Regex;
pub type AST = Vec<(String, Vec<KeyValue>)>;
pub struct KeyValue {
pub key: String,
pub value: String,
}
enum Token {
Section(String),
KeyValue(String, String),
Ignore,
}
pub fn parse(bits: Vec<u8>) -> AST {
let txt = String::from_utf8_lossy(&bits);
let tokens = txt
.split("\n")
.map(tokenize)
.collect();
parse_tokens(tokens)
}
fn tokenize(line: &str) -> Token {
lazy_static! {
static ref SECTION_RE: Regex = Regex::new(r"^\[(.*)\]$").unwrap();
static ref KEY_VALUE_RE: Regex = Regex::new(r"^(\w+)=(.*)$").unwrap();
}
if let Some(captures) = SECTION_RE.captures(line) {
return Token::Section(captures[1].to_string());
}
if let Some(captures) = KEY_VALUE_RE.captures(line) {
return Token::KeyValue(captures[1].to_string(), captures[2].to_string());
}
Token::Ignore
}
fn parse_tokens(tokens: Vec<Token>) -> AST {
let mut acc: Vec<(String, Vec<KeyValue>)> = Vec::new();
for token in tokens {
match token {
Token::Ignore => {
continue;
}
Token::Section(name) => {
acc.push((name, Vec::new()));
}
Token::KeyValue(key, value) => {
if let Some(inner) = acc.last_mut() {
let (_, ref mut key_values) = inner;
key_values.push(KeyValue { key, value })
}
}
}
}
acc
}