pattern-compiler 0.1.0

Utilities for compiling pattern matches into optimal decision trees
Documentation
#[cfg(test)]
mod test;

use ::{ PatternProvider, ExpandedClauseNodes };

use ::petgraph::{ Graph, Direction };
use ::petgraph::graph::NodeIndex;

#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct CfgVar(usize);

use ::std::fmt;
impl fmt::Debug for CfgVar {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "${}", self.0)
    }
}

#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq)]
pub enum NodeKind {
    Tuple,
    ListCell,
    Terminal,
    RootValues,
    Wildcard,
}

#[derive(Debug, Clone)]
pub struct SimplePatternProvider {
    pattern: Graph<NodeKind, ()>,
    roots: Vec<NodeIndex>,
    root_var: CfgVar,
    curr_var: CfgVar,
}

impl SimplePatternProvider {

    pub fn new() -> Self {
        SimplePatternProvider {
            pattern: Graph::new(),
            roots: Vec::new(),
            root_var: CfgVar(0),
            curr_var: CfgVar(0),
        }
    }

    pub fn add_child(&mut self, node: NodeIndex, kind: NodeKind) -> NodeIndex {
        let res = self.pattern.add_node(kind);
        self.pattern.add_edge(node, res, ());
        res
    }

    pub fn add_clause(&mut self, kind: NodeKind) -> NodeIndex {
        let res = self.pattern.add_node(kind);
        self.roots.push(res);
        res
    }
}

impl PatternProvider for SimplePatternProvider {

    type PatternNodeKey = NodeIndex;
    type PatternNodeKind = NodeKind;
    type CfgVariable = CfgVar;

    const WILDCARD: NodeKind = NodeKind::Wildcard;

    fn get_root(&self) -> ExpandedClauseNodes<
            Self::CfgVariable, Self::PatternNodeKey> {
        ExpandedClauseNodes {
            variables: vec![self.root_var],
            clauses: self.roots.len(),
            nodes: self.roots.clone(),
        }
    }

    fn kind_includes(&self, kind: Self::PatternNodeKind,
                     key: Self::PatternNodeKey) -> bool {
        self.pattern[key] == kind
    }

    fn expand_clause_nodes(&mut self, clause_nodes: Vec<Self::PatternNodeKey>)
                           -> ExpandedClauseNodes<
            Self::CfgVariable, Self::PatternNodeKey>
    {
        if clause_nodes.len() == 0 {
            return ExpandedClauseNodes {
                clauses: 0,
                variables: vec![],
                nodes: vec![],
            };
        }

        let typ = self.pattern[clause_nodes[0]];
        let base_len = self.pattern.edges_directed(clause_nodes[0], Direction::Outgoing).count();
        for node in &clause_nodes {
            assert!(self.pattern.edges_directed(clause_nodes[0], Direction::Outgoing).count()
                    == base_len);
            assert!(self.pattern[*node] == typ);
        }

        let mut curr_var = self.curr_var;
        let mut exp = ExpandedClauseNodes {
            clauses: clause_nodes.len(),
            variables: self.pattern
                .edges_directed(clause_nodes[0], Direction::Outgoing)
                .map(|_| {
                    curr_var.0 += 1;
                    curr_var
                })
                .collect(),
            nodes: vec![],
        };
        self.curr_var = curr_var;

        match typ {
            NodeKind::RootValues => {
                for node in &clause_nodes {
                    for child in self.pattern.edges_directed(*node, Direction::Outgoing) {
                        use ::petgraph::visit::EdgeRef;
                        exp.nodes.push(child.target());
                    }
                }
            },
            NodeKind::ListCell => {
                for node in &clause_nodes {
                    for child in self.pattern.edges_directed(*node, Direction::Outgoing) {
                        use ::petgraph::visit::EdgeRef;
                        exp.nodes.push(child.target());
                    }
                }
            },
            NodeKind::Wildcard => {},
            NodeKind::Terminal => {},
            typ => unimplemented!("{:?}", typ),
        }

        println!("{:?}", exp);
        exp
    }

    fn get_kind(&self, key: Self::PatternNodeKey) -> Self::PatternNodeKind {
        self.pattern[key]
    }

}