use std::fmt::{self, Display};
use crate::{Element, Symbol, Value};
pub trait Module<E: Element>: Send + Sync {
fn express<'tape>(&self, input: Value<'tape, E>) -> Value<'tape, E>;
fn visit(&self, visitor: &mut dyn Visitor) {
let _ = visitor;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Segment {
Index(usize),
Name(&'static str),
}
impl Display for Segment {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Segment::Index(index) => write!(formatter, "{index}"),
Segment::Name(name) => write!(formatter, "{name}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path(Vec<Segment>);
impl Path {
pub fn segments(&self) -> &[Segment] {
&self.0
}
}
impl Display for Path {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
for (position, segment) in self.0.iter().enumerate() {
if position > 0 {
write!(formatter, ".")?;
}
write!(formatter, "{segment}")?;
}
Ok(())
}
}
pub trait Visitor {
fn parameter(&mut self, name: &'static str, symbol: Symbol);
fn enter(&mut self, segment: Segment);
fn leave(&mut self);
}
pub fn parameters<E: Element, M: Module<E> + ?Sized>(module: &M) -> Vec<Symbol> {
struct Collector(Vec<Symbol>);
impl Visitor for Collector {
fn parameter(&mut self, _name: &'static str, symbol: Symbol) {
self.0.push(symbol);
}
fn enter(&mut self, _segment: Segment) {}
fn leave(&mut self) {}
}
let mut collector = Collector(Vec::new());
module.visit(&mut collector);
collector.0
}
pub fn named_parameters<E: Element, M: Module<E> + ?Sized>(module: &M) -> Vec<(Path, Symbol)> {
struct Collector {
stack: Vec<Segment>,
named: Vec<(Path, Symbol)>,
}
impl Visitor for Collector {
fn parameter(&mut self, name: &'static str, symbol: Symbol) {
let mut segments = self.stack.clone();
segments.push(Segment::Name(name));
self.named.push((Path(segments), symbol));
}
fn enter(&mut self, segment: Segment) {
self.stack.push(segment);
}
fn leave(&mut self) {
self.stack.pop();
}
}
let mut collector = Collector {
stack: Vec::new(),
named: Vec::new(),
};
module.visit(&mut collector);
collector.named
}
#[cfg(test)]
#[path = "tests/module_tests.rs"]
mod tests;