70 lines
1.9 KiB
Rust
70 lines
1.9 KiB
Rust
use yap::Tokens;
|
|
|
|
use crate::parsing::{newline, parse_n};
|
|
|
|
use super::{Input, Polymer, Rule, Rules};
|
|
|
|
pub fn parse_input(tokens: &mut impl Tokens<Item = char>) -> Option<Input> {
|
|
tokens.optional(|t| {
|
|
let polymer = parse_polymer(t);
|
|
let tag = newline(t) && newline(t);
|
|
let rules = parse_rules(t);
|
|
if let (Some(polymer), true, Some(rules)) = (polymer, tag, rules) {
|
|
Some(Input { polymer, rules })
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn parse_polymer(tokens: &mut impl Tokens<Item = char>) -> Option<Polymer> {
|
|
tokens.optional(|t| {
|
|
let polymer: String = t.many(|t| parse_element(t)).collect();
|
|
if polymer.len() >= 2 {
|
|
polymer.parse().ok()
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn parse_rule(tokens: &mut impl Tokens<Item = char>) -> Option<Rule> {
|
|
tokens.optional(|t| {
|
|
let neighbours = parse_neighbours(t);
|
|
let tag = t.tokens(" -> ".chars());
|
|
let separator = parse_element(t);
|
|
|
|
if let (Some(neighbours), true, Some(separator)) = (neighbours, tag, separator) {
|
|
let neighbours = (neighbours[0], neighbours[1]);
|
|
Some(Rule {
|
|
neighbours,
|
|
separator,
|
|
})
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn parse_neighbours(tokens: &mut impl Tokens<Item = char>) -> Option<[char; 2]> {
|
|
parse_n(tokens, |t| parse_element(t), |_| true)
|
|
}
|
|
|
|
pub fn parse_element(tokens: &mut impl Tokens<Item = char>) -> Option<char> {
|
|
tokens.optional(|t| {
|
|
if let Some(c) = t.next() {
|
|
if c.is_ascii_uppercase() {
|
|
return Some(c);
|
|
}
|
|
}
|
|
None
|
|
})
|
|
}
|
|
|
|
pub fn parse_rules(tokens: &mut impl Tokens<Item = char>) -> Option<Rules> {
|
|
tokens.optional(|t| {
|
|
let rules: Vec<Rule> = t.sep_by(|t| parse_rule(t), |t| newline(t)).collect();
|
|
rules.try_into().ok()
|
|
})
|
|
}
|