use std::{collections::{HashMap, HashSet}, any::Any, error::Error};
use maplit::hashset;
use crate::tool::syntaxis::chiru_visitor::ChiruVisitor;
pub struct ContextVisitor {
nonterminals: HashMap<String, usize>,
terminals: HashMap<String, usize>,
pub table: HashMap<usize, (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>)>,
}
impl ContextVisitor {
pub fn new(nonterminals: HashMap<String, usize>, terminals: HashMap<String, usize>) -> Self {
Self {
table: HashMap::new(),
nonterminals,
terminals,
}
}
}
impl ChiruVisitor for ContextVisitor {
fn visit_compilation_unit(&mut self, ctx: &dyn crate::tool::syntaxis::chiru_context::CompilationUnitContext) -> Result<Box<dyn Any>, Box<dyn Error>> {
if let Some(rules) = ctx.rules() {
rules.accept(self)
} else {
self.default_result()
}
}
fn visit_rules(&mut self, ctx: &dyn crate::tool::syntaxis::chiru_context::RulesContext) -> Result<Box<dyn Any>, Box<dyn Error>> {
for ctx in ctx.parser_rule_list().iter() {
ctx.accept(self)?;
}
self.default_result()
}
fn visit_parser_rule(&mut self, ctx: &dyn crate::tool::syntaxis::chiru_context::ParserRuleContext) -> Result<Box<dyn Any>, Box<dyn Error>> {
let name = &ctx.rule_ref().unwrap().symbol.text;
let id = *self.nonterminals.get(name).unwrap();
let result = ctx.block().unwrap().accept(self)?.downcast::<(HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>)>().unwrap();
self.table.insert(id, *result);
self.default_result()
}
fn visit_block(&mut self, ctx: &dyn crate::tool::syntaxis::chiru_context::BlockContext) -> Result<Box<dyn Any>, Box<dyn Error>> {
let mut result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) = (HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new());
for v in ctx.alternative_list().iter() {
let re = v.accept(self)?.downcast::<(HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>)>().unwrap();
result.0.extend(re.0);
result.1.extend(re.1);
result.2.extend(re.2);
result.3.extend(re.3);
}
Ok(Box::new(result))
}
fn visit_alternative(&mut self, ctx: &dyn crate::tool::syntaxis::chiru_context::AlternativeContext) -> Result<Box<dyn Any>, Box<dyn Error>> {
let mut result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) = (HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new());
let mut children: Vec<Box<(HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>)>> = Vec::new();
for elem in ctx.element_list().iter() {
let child = elem.accept(self)?.downcast::<(HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>)>().unwrap();
children.push(child);
}
for child in children.iter() {
result.0.extend(&child.0);
result.2.extend(&child.2);
}
for child in children.iter() {
for terminal in child.1.iter() {
if result.1.contains(terminal) {
result.0.insert(*terminal);
result.1.remove(terminal);
} else if result.0.contains(terminal) {
continue;
}
else {
result.1.insert(*terminal);
}
}
for nonterminal in child.3.iter() {
if result.3.contains(nonterminal) {
result.2.insert(*nonterminal);
result.3.remove(nonterminal);
} else if result.2.contains(nonterminal) {
continue;
}
else {
result.3.insert(*nonterminal);
}
}
}
Ok(Box::new(result))
}
fn visit_element(&mut self, ctx: &dyn crate::tool::syntaxis::chiru_context::ElementContext) -> Result<Box<dyn Any>, Box<dyn Error>> {
if let Some(token) = ctx.token_ref() {
let name = &token.symbol.text;
let token_id = self.terminals.get(name).unwrap();
if let Some(suffix) = ctx.ebnf_suffix() {
if let Some(_) = suffix.star() {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! { *token_id }, hashset! {}, hashset! {}, hashset! {});
return Ok(Box::new(result));
} else if let Some(_) = suffix.plus() {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! { *token_id }, hashset! {}, hashset! {}, hashset! {});
return Ok(Box::new(result));
} else {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! {}, hashset! { *token_id }, hashset! {}, hashset! {});
return Ok(Box::new(result));
}
} else {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! {}, hashset! { *token_id }, hashset! {}, hashset! {});
return Ok(Box::new(result));
}
}
else if let Some(rule) = ctx.rule_ref() {
let name = &rule.symbol.text;
let rule_id = self.nonterminals.get(name).unwrap();
if let Some(suffix) = ctx.ebnf_suffix() {
if let Some(_) = suffix.star() {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! {}, hashset! {}, hashset! { *rule_id }, hashset! {});
return Ok(Box::new(result));
} else if let Some(_) = suffix.plus() {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! {}, hashset! {}, hashset! { *rule_id }, hashset! {});
return Ok(Box::new(result));
} else {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! {}, hashset! {}, hashset! {}, hashset! { *rule_id });
return Ok(Box::new(result));
}
} else {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! {}, hashset! {}, hashset! {}, hashset! { *rule_id });
return Ok(Box::new(result));
}
} else if let Some(block) = ctx.block() {
let mut result = block.accept(self)?.downcast::<(HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>)>().unwrap();
if let Some(suffix) = ctx.ebnf_suffix() {
if let Some(_) = suffix.star() {
result.0.extend(&result.1);
result.2.extend(&result.3);
result.1.clear();
result.3.clear();
return Ok(result);
} else if let Some(_) = suffix.plus() {
result.0.extend(&result.1);
result.2.extend(&result.3);
result.1.clear();
result.3.clear();
return Ok(result);
}
}
return Ok(result);
} else {
let result: (HashSet<usize>, HashSet<usize>, HashSet<usize>, HashSet<usize>) =
(hashset! {}, hashset! {}, hashset! {}, hashset! {});
return Ok(Box::new(result));
}
}
}