use std::collections::{HashMap, HashSet};
use chiru::runtime::{error_strategy::error_listener::{ErrorListener, ConsoleErrorListener}, lexer_rule::LexerRule, lexer::{Lexer, TokenIter}, production::Production, token_stream::TokenStream, ast::rule_context::RuleContext, ll1_analyzer::ll1_analyze};
use super::grammar::Grammar;
pub struct CommonLexer<'a> {
pub input: &'a str,
pub error_listeners: Vec<Box<dyn ErrorListener>>,
pub rules: Vec<LexerRule>,
}
impl Lexer for CommonLexer<'_> {
fn iter(&self) -> chiru::runtime::lexer::TokenIter {
TokenIter::new(self.input, &self.rules, &self.error_listeners)
}
}
impl<'a> CommonLexer<'a> {
pub fn from_grammar(grammar: &Grammar, input: &'a str) -> Self {
let rules = grammar.lexer_rule_map.values().map(|v| {
let re = regex::Regex::new(r####"(^r#*")|("#*$)"####).unwrap();
let c = re.replace_all(&v.regex, "");
let rule = regex::Regex::new(&c).unwrap();
return LexerRule {
channel: v.channel,
token_type: v.token_type,
token_name: v.token_name.to_owned(),
skip: v.skip,
rule
};
}).collect::<Vec<_>>();
Self {
input,
rules,
error_listeners: vec![Box::new(ConsoleErrorListener::new())],
}
}
}
pub struct CommonParser {
pub error_listeners: Vec<Box<dyn ErrorListener>>,
pub table: HashMap<(usize, usize), usize>,
pub productions: HashMap<usize, Production>,
pub nonterminals: HashMap<usize, String>,
pub sync: HashSet<(usize, usize)>,
}
impl CommonParser {
pub fn parse(&self, token_stream: &mut TokenStream, rule_index: usize) -> RuleContext {
ll1_analyze(token_stream, rule_index, &self.table, &self.productions, &self.nonterminals, &self.sync, &self.error_listeners).unwrap()
}
pub fn from_grammar(grammar: &Grammar) -> Self {
let (first, first_set) = grammar.first_set();
let follow = grammar.follow_set(&first);
let table = grammar.ll1_table(&first_set, &follow);
let productions = grammar.productions.clone();
let mut sync: HashSet<(usize, usize)> = HashSet::new();
for (id, followers) in follow.iter() {
for x in followers.iter() {
sync.insert((*id, *x));
}
}
let mut nonterminals = HashMap::new();
for (k, v) in grammar.vocabulary.nonterminals.iter() {
if let Some(name) = &v.name {
nonterminals.insert(*k, name.to_owned());
}
}
Self {
table, productions, sync, nonterminals, error_listeners: vec![Box::new(ConsoleErrorListener::new())],
}
}
}