rust_dot 0.6.0

RustDOT is mostly the Graphviz DOT language, lightly rustified.
Documentation
/*!
This does the bulk of graph parsing, including subgraphs nested at any depth.
*/
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};

/* enum Label {
    Str(Cow<'static, str>),
    Fn(Lexeme)
} */
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,
    //node: Label,
    //edge: Label,
}

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,
            //node: Label::Str(r"\N".into()),
            //edge: Label::Str("".into()),
        };
        let _ = graph // the nodes are stored, no need to know again which they were.
            .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));
        //node_label: self.node_label.clone(), //node_handler: Lexeme,
        //edge_label: self.edge_label.clone(), //edge_handler: Lexeme,
        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();
        } // todo

        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 {
        //println!("add_node {name} {in_chain}");
        if !in_chain {
            while peek!(self.lexer, Attrs(_)) {
                self.lexer.next();
            } // todo
        }
        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) {
        //println!("add_edges {tails:?} {heads:?}");
        while peek!(self.lexer, Attrs(_)) {
            self.lexer.next();
        } // todo
          // todo if self.strict {}
        for tail in tails {
            for head in heads {
                //println!("{} -- {}", *tail, *head);
                self.edges.push((*tail, *head));
            }
        }
    }
}