pub mod eval;
#[cfg(test)]
mod test;
use std::{
collections::{BTreeMap, BTreeSet},
error::Error,
fmt::Display,
};
use crate::{
matching::get_match_bindings,
parser::{self, ParseError},
};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Token {
Element(String),
Literal(String),
}
impl Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use termion::{
color::{Fg, LightMagenta},
style::Reset,
};
match self {
Token::Element(element) => write!(f, "{}{element}{}", Fg(LightMagenta), Reset)?,
Token::Literal(literal) => write!(f, "{literal}")?,
}
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PatternToken {
Concrete(Token),
Variable(String),
SpreadVariable(String),
}
impl Display for PatternToken {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use termion::style::{Bold, Italic, Reset};
match self {
Self::Concrete(token) => write!(f, "{token}"),
Self::Variable(name) => write!(f, "{}{name}{}", Bold, Reset),
Self::SpreadVariable(name) => write!(f, "{}{}{name}{}", Bold, Italic, Reset),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Expression {
pub tokens: Vec<Token>,
}
impl Expression {
pub fn new(tokens: Vec<Token>) -> Self {
Self { tokens }
}
}
impl PartialOrd for Expression {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match self.tokens.len().partial_cmp(&other.tokens.len())? {
std::cmp::Ordering::Equal => self.tokens.partial_cmp(&other.tokens),
ordering => ordering.into(),
}
}
}
impl Ord for Expression {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self.tokens.len().cmp(&other.tokens.len()) {
std::cmp::Ordering::Equal => self.tokens.cmp(&other.tokens),
ordering => ordering,
}
}
}
impl From<&[Token]> for Expression {
fn from(tokens: &[Token]) -> Self {
Self {
tokens: tokens.to_vec(),
}
}
}
impl Display for Expression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for token in &self.tokens {
write!(f, "{} ", token)?;
}
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Definition {
low: Vec<PatternToken>,
high: Vec<PatternToken>,
}
impl Definition {
pub fn new(lhs: Vec<PatternToken>, rhs: Vec<PatternToken>) -> Self {
Self {
high: lhs,
low: rhs,
}
}
fn transform<'a>(
from: &[PatternToken],
to: &[PatternToken],
expression: &'a [Token],
) -> Option<Expression> {
let (single_bindings, spread_bindings) = get_match_bindings(from, expression)?;
let mut result = Vec::new();
for token in to {
match token {
PatternToken::Concrete(token) => result.push(token.clone()),
PatternToken::Variable(name) => {
let binding = *single_bindings.get(name)?;
result.push(binding.clone());
}
PatternToken::SpreadVariable(name) => {
let binding = spread_bindings.get(name)?;
result.extend_from_slice(binding);
}
};
}
Some(Expression::new(result))
}
pub fn lower(&self, expression: &[Token]) -> Option<Expression> {
Self::transform(&self.high, &self.low, expression)
}
pub fn raise(&self, expression: &[Token]) -> Option<Expression> {
Self::transform(&self.low, &self.high, expression)
}
}
impl Display for Definition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for token in &self.high {
write!(f, "{} ", token)?;
}
write!(f, "=> ")?;
for token in &self.low {
write!(f, "{} ", token)?;
}
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Structure {
domain: BTreeSet<String>,
reserved: BTreeSet<String>,
definitions: Vec<Definition>,
}
impl Structure {
pub fn create(
domain: BTreeSet<String>,
reserved: BTreeSet<String>,
definitions: Vec<Definition>,
) -> Result<Self, StructureError> {
if let Some(culprit) = domain.iter().find(|d| reserved.contains(*d)) {
return Err(StructureError::DomainAndReservedOverlap {
culprit: culprit.to_owned(),
});
}
Ok(Self {
domain,
reserved,
definitions,
})
}
pub fn intrinsic() -> Self {
let reserved = BTreeSet::from(["{", "}", ",", "(", ")", "="].map(|s| s.to_owned()));
Structure {
domain: BTreeSet::new(),
reserved,
definitions: Vec::new(),
}
}
pub fn empty() -> Self {
Structure {
domain: BTreeSet::new(),
reserved: BTreeSet::new(),
definitions: Vec::new(),
}
}
pub fn get_reserved(&self) -> &BTreeSet<String> {
&self.reserved
}
pub fn get_domain(&self) -> &BTreeSet<String> {
&self.domain
}
}
impl Display for Structure {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let domain: Vec<_> = self.domain.iter().cloned().collect();
writeln!(f, "Domain: {{ {} }}", domain.join(", "))?;
let reserved: Vec<_> = self.reserved.iter().cloned().collect();
writeln!(f, "Reserved: {{ {} }}", reserved.join(", "))?;
writeln!(f, "Definitions: ")?;
for definition in &self.definitions {
writeln!(f, "- {definition};")?;
}
Ok(())
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum StructureError {
DomainAndReservedOverlap { culprit: String },
}
impl Display for StructureError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StructureError::DomainAndReservedOverlap { culprit } => {
write!(
f,
"Domain and reserved keywords overlap (\"{}\" appears in both)",
culprit
)
}
}
}
}
impl Error for StructureError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Runtime {
pub structures: BTreeMap<String, Structure>,
}
impl Runtime {
pub fn new(structures: BTreeMap<String, Structure>) -> Self {
Self { structures }
}
pub fn domain(&self) -> impl Iterator<Item = &String> + '_ {
self.structures
.iter()
.flat_map(|(_name, structure)| structure.domain.iter())
}
pub fn reserved(&self) -> impl Iterator<Item = &String> + '_ {
self.structures
.iter()
.flat_map(|(_name, structure)| structure.reserved.iter())
}
pub fn definitions(&self) -> impl Iterator<Item = &Definition> + '_ {
self.structures
.iter()
.flat_map(|(_name, structure)| structure.definitions.iter())
}
pub fn contains(&self, name: &str) -> bool {
self.structures.contains_key(name)
}
pub fn insert(&mut self, name: String, structure: Structure) -> Option<Structure> {
self.structures.insert(name, structure)
}
pub fn from_partial(structures: &BTreeMap<String, Option<Structure>>) -> Self {
let mut runtime = Runtime::new(BTreeMap::new());
for (name, structure) in structures {
if let Some(structure) = structure {
runtime.insert(name.to_owned(), structure.to_owned());
}
}
runtime
}
pub fn parse_expression(&self, expression: &str) -> Result<Expression, ParseError> {
parser::expression(expression, self)
}
}
impl Display for Runtime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (name, structure) in &self.structures {
writeln!(f, "{name}:")?;
writeln!(f, "{structure}")?;
}
Ok(())
}
}