use std::convert::AsRef;
use crate::history::{HistoryNodeAssignPrecedence, HistoryNodeRhs, RootHistoryNode};
use crate::prelude::*;
use crate::rule::builder::RuleBuilder;
use crate::rule::{GrammarRule, Rule};
use self::Associativity::*;
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Associativity {
Left,
Right,
Group,
}
pub const DEFAULT_ASSOC: Associativity = Left;
pub struct PrecedencedRuleBuilder<D>
where
D: RuleContainer,
{
rules: D,
lhs: Symbol,
tighter_lhs: Symbol,
current_lhs: Symbol,
history: Option<HistoryId>,
assoc: Associativity,
looseness: u32,
rules_with_group_assoc: Vec<Rule>,
}
impl<D> PrecedencedRuleBuilder<D>
where
D: RuleContainer,
{
pub fn new(mut rules: D, lhs: Symbol) -> Self {
let tightest_lhs = rules.next_sym();
PrecedencedRuleBuilder {
rules,
lhs: lhs,
tighter_lhs: tightest_lhs,
current_lhs: tightest_lhs,
history: None,
assoc: Left,
looseness: 0,
rules_with_group_assoc: vec![],
}
}
}
impl<D> PrecedencedRuleBuilder<D>
where
D: RuleContainer,
{
pub fn precedenced_rule(self, lhs: Symbol) -> PrecedencedRuleBuilder<D> {
self.finalize().precedenced_rule(lhs)
}
pub fn rule(self, lhs: Symbol) -> RuleBuilder<D> {
self.finalize().rule(lhs)
}
#[must_use]
pub fn history(mut self, history: HistoryId) -> Self {
self.history = Some(history);
self
}
#[must_use]
pub fn rhs<S>(mut self, syms: S) -> Self
where
S: AsRef<[Symbol]>,
{
let history_id = self.history.take().unwrap_or_else(|| {
self.rules
.add_history_node(RootHistoryNode::Rule { lhs: self.lhs }.into())
});
let history_id = self.rules.add_history_node(
HistoryNodeRhs {
prev: history_id,
rhs: syms.as_ref().to_vec(),
}
.into(),
);
self.rhs_with_history(syms.as_ref(), history_id)
}
#[must_use]
pub fn rhs_with_history<S>(mut self, syms: S, history_id: HistoryId) -> Self
where
S: AsRef<[Symbol]>,
{
let syms = syms.as_ref();
let history_assign_precedence = self.rules.add_history_node(
HistoryNodeAssignPrecedence {
prev: history_id,
looseness: self.looseness,
}
.into(),
);
let lhs = self.lhs;
let mut syms = syms.to_vec();
if self.assoc == Group {
self.rules_with_group_assoc.push(Rule::new(
self.current_lhs,
syms,
history_assign_precedence,
));
} else {
{
let mut iter = syms.iter_mut().filter(|&&mut sym| sym == lhs);
let extreme_sym_mut = if self.assoc == Left {
iter.next()
} else {
iter.next_back()
};
if let Some(extreme_sym) = extreme_sym_mut {
*extreme_sym = self.current_lhs;
}
for sym in iter {
*sym = self.tighter_lhs;
}
};
self.rules
.add_rule(self.current_lhs, &syms[..], history_assign_precedence);
}
self.assoc = DEFAULT_ASSOC;
self.history = None;
self
}
#[must_use]
pub fn associativity(mut self, assoc: Associativity) -> Self {
self.assoc = assoc;
self
}
#[must_use]
pub fn lower_precedence(mut self) -> Self {
self.looseness += 1;
self.tighter_lhs = self.current_lhs;
self.current_lhs = self.rules.next_sym();
let history_id = self.rules.add_history_node(RootHistoryNode::NoOp.into());
RuleBuilder::new(&mut self.rules)
.rule(self.current_lhs)
.rhs_with_history(&[self.tighter_lhs], history_id);
self
}
pub fn finalize(mut self) -> RuleBuilder<D> {
let loosest_lhs = self.current_lhs;
for mut rule in self.rules_with_group_assoc.drain(..) {
for sym in &mut rule.rhs {
if *sym == self.lhs {
*sym = loosest_lhs;
}
}
self.rules
.add_rule(rule.lhs(), &rule.rhs[..], rule.history_id());
}
let history_id = self.rules.add_history_node(RootHistoryNode::NoOp.into());
RuleBuilder::new(self.rules)
.rule(self.lhs)
.rhs_with_history(&[loosest_lhs], history_id)
}
}