use std::collections::HashMap;
use std::rc::Rc;
use crate::lexer::{lexer, Lexeme::*, Lexer};
type NodeSet = std::collections::HashSet<usize>;
use proc_macro2::{Group, TokenStream};
pub struct Parser {
pub strict: bool,
pub directed: bool,
pub name: String,
pub nodes: Vec<Rc<str>>,
node_map: HashMap<Rc<str>, usize>,
pub edges: Vec<(usize, usize)>,
lexer: Lexer,
parse_fn: bool,
}
impl Parser {
pub fn graph(
strict: bool,
directed: bool,
name: String,
block: TokenStream,
parse_fn: bool,
) -> Self {
let mut graph = Parser {
name,
strict,
directed,
nodes: vec![],
node_map: HashMap::new(),
edges: vec![],
lexer: lexer(block, parse_fn),
parse_fn,
};
let _ = graph .parse_block();
graph
}
pub fn recurse(&mut self, input: Group) -> NodeSet {
use std::mem::replace;
let lexer = replace(&mut self.lexer, lexer(input.stream(), self.parse_fn));
let result = self.parse_block();
let _ = replace(&mut self.lexer, lexer);
result
}
pub fn parse_block(&mut self) -> NodeSet {
let mut nodes = NodeSet::new();
loop {
let item = self.lexer.next();
if item.is_none() {
break;
}
match item.unwrap() {
x @ Graph | x @ Node | x @ Edge => {
if !next_if!(self.lexer, Attrs(_)) {
panic!("After {x:?} expected attrs\n");
}
}
Id(str) | Html(str) if next_if!(self.lexer, Other('=')) => {
if !next_if!(self.lexer, Id(_) | Html(_)) {
panic!("After {str} = expected id\n");
}
}
Block(block) => {
if peek!(self.lexer, EdgeOp(_)) {
let start = self.recurse(block);
self.parse_chain(&mut nodes, start);
} else {
nodes.extend(self.recurse(block));
}
}
NodeId(id) | Id(id) | Html(id) => {
if peek!(self.lexer, EdgeOp(_)) {
let start = NodeSet::from([self.add_node(id, true)]);
self.parse_chain(&mut nodes, start);
} else {
nodes.insert(self.add_node(id, false));
}
}
x => panic!("At beginning of statement didn't expect {x:?}\n"),
};
next_if!(self.lexer, Other(';'));
}
nodes
}
fn parse_chain(&mut self, nodes: &mut NodeSet, start: NodeSet) {
let mut chain = vec![start];
loop {
if !next_if!(self.lexer, EdgeOp(directed) if *directed == self.directed) {
break;
}
let item = self.lexer.next();
if item.is_none() {
panic!("After edge op expected node or subgraph.")
}
chain.push(match item.unwrap() {
Block(block) => self.recurse(block),
NodeId(id) | Id(id) | Html(id) => NodeSet::from([self.add_node(id, true)]),
x => panic!("After edge op didn't expect {x:?}\n"),
});
}
while peek!(self.lexer, Attrs(_)) {
self.lexer.next();
}
let mut subgraphs = chain.iter().peekable();
while let Some(tails) = subgraphs.next() {
nodes.extend(tails);
if let Some(heads) = subgraphs.peek() {
self.add_edges(tails, heads);
}
}
}
fn add_node(&mut self, name: String, in_chain: bool) -> usize {
if !in_chain {
while peek!(self.lexer, Attrs(_)) {
self.lexer.next();
} }
let name: Rc<str> = name.into();
let name_clone = Rc::clone(&name);
*self.node_map.entry(name).or_insert_with(|| {
self.nodes.push(name_clone);
self.nodes.len() - 1
})
}
fn add_edges(&mut self, tails: &NodeSet, heads: &NodeSet) {
while peek!(self.lexer, Attrs(_)) {
self.lexer.next();
} for tail in tails {
for head in heads {
self.edges.push((*tail, *head));
}
}
}
}