lr_parser 0.1.2

macros for ruly2
Documentation
use std::collections::{HashMap, HashSet};

use crate::item::Item;

pub fn compute_first_sets(
    nonterminal_symbols: &HashSet<String>,
    map_lhs2items: &HashMap<String, HashSet<Item>>,
) -> HashMap<Vec<String>, HashSet<Option<String>>> {
    let mut first_sets = {
        let mut tmp = HashMap::from([(vec![], HashSet::from([None]))]);

        for (_, item_set) in map_lhs2items {
            for item in item_set {
                let lhs = item.get_lhs();
                let rhs = item.get_rhs();

                tmp.insert(vec![lhs.to_string()], HashSet::new());

                for i in 0..rhs.len() {
                    tmp.insert(rhs[i..].to_vec(), HashSet::new());
                }
            }
        }

        tmp
    };

    loop {
        let mut not_changed = true;

        for (_, item_set) in map_lhs2items {
            for item in item_set {
                let lhs = item.get_lhs();
                let rhs = &item.get_rhs()[..];

                for i in (0..rhs.len()).rev() {
                    let w = &rhs[i..];
                    let a = w.first().expect("6");

                    let new_set = if nonterminal_symbols.contains(a) {
                        let mut first_set_of_a =
                            first_sets.get(&vec![a.to_string()]).unwrap().clone();

                        if first_set_of_a.remove(&None) {
                            first_set_of_a
                                .union(first_sets.get(&w[1..]).expect("8"))
                                .into_iter()
                                .map(|x| x.clone())
                                .collect()
                        } else {
                            first_set_of_a
                        }
                    } else {
                        HashSet::from([Some(a.to_string())])
                    };
                    let old_set = first_sets.get(w).expect("2");

                    if !old_set.is_superset(&new_set) {
                        *first_sets.get_mut(w).expect("3") =
                            old_set.union(&new_set).map(|s| s.clone()).collect();
                        not_changed = false;
                    }
                }

                let new_set = first_sets.get(rhs).expect("4");
                let old_set = first_sets.get(&vec![lhs.to_string()]).expect("5");

                if !old_set.is_superset(&new_set) {
                    *first_sets.get_mut(&vec![lhs.to_string()]).expect("1") =
                        old_set.union(&new_set).map(|s| s.clone()).collect();
                    not_changed = false;
                }
            }
        }

        if not_changed {
            break;
        }
    }

    first_sets
}