use crate::*;
use std::fmt::Debug;
use std::fmt::Display;
use std::ops::Range;
use std::ops::RangeBounds;
#[derive(Debug, Clone, AsRef)]
pub struct Chart<T> {
table: Vec<Vec<Vec<Item<T>>>>,
history: Vec<Vec<Item<T>>>,
}
impl<T> Default for Chart<T> {
fn default() -> Self { Self::new() }
}
impl<T> Chart<T> {
pub fn new() -> Self { Self { table: Vec::new(), history: Vec::new() } }
pub(crate) fn range_from(&self, bounds: impl RangeBounds<usize>) -> Range<usize> {
use std::ops::Bound::*;
let len = self.table.len();
let start = match bounds.start_bound() {
Included(&start) => start,
Excluded(&start) => start + 1,
Unbounded => 0,
};
let end = match bounds.end_bound() {
Included(&end) => end + 1,
Excluded(&end) => end,
Unbounded => len,
};
usize::min(start, len)..usize::min(end, len)
}
pub fn rows(&self) -> &Vec<Vec<Vec<Item<T>>>> { &self.table }
fn rows_mut(&mut self) -> &mut Vec<Vec<Vec<Item<T>>>> { &mut self.table }
pub fn row(&self, cursor: usize) -> Option<&Vec<Vec<Item<T>>>> { self.table.get(cursor) }
fn row_mut(&mut self, cursor: usize) -> Option<&mut Vec<Vec<Item<T>>>> {
self.table.get_mut(cursor)
}
pub fn cell(&self, cursor: usize, offset: usize) -> Option<&Vec<Item<T>>> {
self.row(cursor).and_then(|row| row.get(offset))
}
fn cell_mut(&mut self, cursor: usize, offset: usize) -> Option<&mut Vec<Item<T>>> {
self.row_mut(cursor).and_then(|row| {
if offset < cursor + 1 {
if row.len() <= offset {
row.resize(offset + 1, Default::default())
}
Some(row.get_mut(offset).unwrap())
} else {
None
}
})
}
pub fn items_horizontally_on(
&self,
cursor: usize,
) -> impl Iterator<Item = &Item<T>> + DoubleEndedIterator {
self.row(cursor).into_iter().flatten().flatten()
}
pub fn items_diagonally_within(
&self,
bounds: impl RangeBounds<usize>,
) -> impl Iterator<Item = &Item<T>> + DoubleEndedIterator {
self.range_from(bounds)
.into_iter()
.enumerate()
.filter_map(|(offset, cursor)| self.cell(cursor, offset))
.flatten()
}
fn shrink_to_fit(&mut self, cursor: usize) {
if let Some(row) = self.row_mut(cursor) {
while let Some(cell_last) = row.last() {
if cell_last.is_empty() {
row.pop();
} else {
break;
}
}
row.shrink_to_fit();
}
}
fn reductions_for(&self, reducer: &Reducer<T>) -> impl '_ + Iterator<Item = Reduction<T>> {
let (cursor, offset) = reducer.address();
let cursor = (cursor - offset).checked_sub(1);
cursor
.into_iter()
.flat_map(|cursor| self.items_horizontally_on(cursor).filter_map(Item::reduction))
.cloned()
}
fn reducers_for(&self, reduction: &Reduction<T>) -> impl '_ + Iterator<Item = Reducer<T>> {
let cursor = reduction.cursor() + 1;
self.items_diagonally_within(cursor..).filter_map(Item::reducer).cloned()
}
fn reduce_from_grammar<'a>(
&'a self,
reducer: Reducer<T>,
grammar: &'a [&Ruleset<T>],
) -> impl 'a + Iterator<Item = (Reducible<T>, Reducer<T>)> {
grammar
.into_iter()
.flat_map(|ruleset| ruleset.rules())
.map(Reducible::from)
.zip(std::iter::repeat(reducer.clone()))
}
fn reduce_from_chart(
&self,
reducer: Reducer<T>,
) -> impl '_ + Iterator<Item = (Reducible<T>, Reducer<T>)> {
self.reductions_for(&reducer)
.map(Reducible::try_from)
.filter_map(std::result::Result::ok)
.zip(std::iter::repeat(reducer))
}
fn reduce_from_subrule<'a>(
&'a self,
reduction: Reduction<T>,
) -> impl 'a + Iterator<Item = (Reducible<T>, Reducer<T>)> {
let reducers = self.reducers_for(&reduction);
Reducible::try_from(reduction)
.into_iter()
.flat_map(|reducible| std::iter::repeat(reducible))
.zip(reducers)
}
fn plot(&mut self, item: Item<T>) {
let (cursor, offset) = item.address();
let cell = self.cell_mut(cursor, offset).unwrap();
cell.push(item.clone());
self.history.last_mut().unwrap().push(item);
}
fn plot_reducer(&mut self, reducer: Reducer<T>, grammar: &[&Ruleset<T>]) {
let item = Item::from(reducer.clone());
self.plot(item);
self.seminate_reductions(reducer, grammar);
}
fn plot_reduction(&mut self, reduction: Reduction<T>, grammar: &[&Ruleset<T>]) {
let item = Item::from(reduction.clone());
self.plot(item);
self.seminate_reducers(reduction, grammar);
}
fn reduce(
&self,
parents: impl IntoIterator<Item = (Reducible<T>, Reducer<T>)>,
) -> Vec<Reduction<T>> {
let mut reductions = Vec::new();
for (reducible, reducer) in parents {
match reducible.reduce(&*reducer) {
Match::Hit { reductum } => {
let reduction = Reduction::new(reducible, reducer, reductum);
reductions.push(reduction);
}
Match::Miss => {}
Match::Error { reason } => {
}
}
}
reductions
}
fn seminate_reductions(&mut self, reducer: Reducer<T>, grammar: &[&Ruleset<T>]) {
let from_grammar = self.reduce_from_grammar(reducer.clone(), grammar);
let from_chart = self.reduce_from_chart(reducer);
let reductions = self.reduce(from_grammar.chain(from_chart));
for reduction in reductions {
self.plot_reduction(reduction, grammar);
}
}
fn seminate_reducers(&mut self, reduction: Reduction<T>, grammar: &[&Ruleset<T>]) {
if let Some(consequence) = reduction.reductum().consequence() {
let mut antecedents = reduction.antecedents();
let consequents = consequence.consequents();
for (index, consequent) in consequents.into_iter().enumerate() {
if let Some(consequent) = consequent {
let antecedents = consequent.take_relevant(&mut antecedents);
let conclusion = Conclusion::new(reduction.clone(), index, antecedents);
self.plot_reducer(conclusion.into(), grammar);
} else {
antecedents.next().unwrap();
}
}
debug_assert!(antecedents.count() == 0);
}
else {
let from_subrule = self.reduce_from_subrule(reduction);
let reductions = self.reduce(from_subrule);
for reduction in reductions {
self.plot_reduction(reduction, grammar);
}
}
}
pub fn push(&mut self, input: T, grammar: &[&Ruleset<T>]) {
let cursor = self.table.len();
let mut row = Vec::with_capacity(cursor + 1);
row.resize(cursor + 1, Default::default());
self.table.push(row);
self.history.push(Default::default());
let input = Input::new(input, cursor);
self.plot_reducer(input.into(), grammar);
self.shrink_to_fit(cursor);
}
pub fn pop(&mut self) -> Option<Input<T>> {
self.table.pop();
if let Some(mut items) = self.history.pop() {
while 1 < items.len() {
let item = items.pop().unwrap();
let (cursor, offset) = item.address();
if let Some(cell) = self.cell_mut(cursor, offset) {
cell.pop();
}
}
items.pop().unwrap().into_reducer().and_then(Reducer::into_input)
} else {
None
}
}
fn determine(&mut self, interpretation: impl AsRef<Reducer<T>>) {
let interpretation = interpretation.as_ref();
let (cursor, offset) = interpretation.address();
let range = interpretation.range();
for index in range.start..cursor {
let row = self.row_mut(index).unwrap();
let cell_first = row.first_mut().unwrap();
cell_first.splice(1.., []);
cell_first.shrink_to_fit();
for cell in row.iter_mut().skip(1) {
cell.clear();
cell.shrink_to_fit();
}
row.shrink_to_fit();
}
let row_last = self.row_mut(cursor).unwrap();
let cell_first = row_last.first_mut().unwrap();
cell_first.splice(1.., []);
cell_first.shrink_to_fit();
for cell in row_last.iter_mut().skip(1).take(offset - 1) {
cell.clear();
cell.shrink_to_fit();
}
let width = offset;
for cell in self
.table
.iter_mut()
.skip(cursor + 1)
.enumerate()
.flat_map(|(offset, row)| row.iter_mut().skip(offset + 1).take(width))
{
cell.clear();
cell.shrink_to_fit();
}
}
pub fn len(&self) -> usize { self.table.len() }
pub fn is_empty(&self) -> bool { self.table.is_empty() }
}
impl<T: Display> Display for Chart<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use comfy_table::presets::UTF8_FULL;
use comfy_table::*;
let mut table = Table::new();
table.load_preset(UTF8_FULL);
for (index, row) in self.table.iter().enumerate() {
let mut row = row
.iter()
.map(|items| items.iter().map(|item| format!("{item:.4}\n")).collect::<String>())
.collect::<Vec<_>>();
row.resize(index + 1, Default::default());
table.add_row(row);
}
write!(f, "{}", table)?;
Ok(())
}
}