pink_runtime/engine/
mod.rs

1pub mod eval;
2
3#[cfg(test)]
4mod test;
5
6use std::{
7    collections::{BTreeMap, BTreeSet},
8    error::Error,
9    fmt::Display,
10};
11
12use crate::{
13    matching::get_match_bindings,
14    parser::{self, ParseError},
15};
16
17#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
18pub enum Token {
19    /// An actual element of the domain of a structure
20    Element(String),
21
22    /// A string of text with no inherent meaning other than to be a shorcut for a more complicated expression
23    /// Think of it as syntax
24    Literal(String),
25}
26
27impl Display for Token {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        use termion::{
30            color::{Fg, LightMagenta},
31            style::Reset,
32        };
33        match self {
34            Token::Element(element) => write!(f, "{}{element}{}", Fg(LightMagenta), Reset)?,
35
36            // TODO: I'm afraid something could be wrong here in different terminals
37            Token::Literal(literal) => write!(f, "{literal}")?,
38        }
39
40        Ok(())
41    }
42}
43
44#[derive(Debug, PartialEq, Eq, Clone)]
45pub enum PatternToken {
46    /// Either element or literal
47    Concrete(Token),
48
49    /// Variable that binds to only one token
50    Variable(String),
51
52    /// Variable that binds arbitrary number of tokens
53    SpreadVariable(String),
54}
55
56impl Display for PatternToken {
57    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58        use termion::style::{Bold, Italic, Reset};
59
60        match self {
61            Self::Concrete(token) => write!(f, "{token}"),
62            Self::Variable(name) => write!(f, "{}{name}{}", Bold, Reset),
63            Self::SpreadVariable(name) => write!(f, "{}{}{name}{}", Bold, Italic, Reset),
64        }
65    }
66}
67
68#[derive(Debug, PartialEq, Eq, Clone)]
69pub struct Expression {
70    pub tokens: Vec<Token>,
71}
72
73impl Expression {
74    pub fn new(tokens: Vec<Token>) -> Self {
75        Self { tokens }
76    }
77}
78
79impl PartialOrd for Expression {
80    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
81        match self.tokens.len().partial_cmp(&other.tokens.len())? {
82            std::cmp::Ordering::Equal => self.tokens.partial_cmp(&other.tokens),
83            ordering => ordering.into(),
84        }
85    }
86}
87
88impl Ord for Expression {
89    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
90        match self.tokens.len().cmp(&other.tokens.len()) {
91            std::cmp::Ordering::Equal => self.tokens.cmp(&other.tokens),
92            ordering => ordering,
93        }
94    }
95}
96
97impl From<&[Token]> for Expression {
98    fn from(tokens: &[Token]) -> Self {
99        Self {
100            tokens: tokens.to_vec(),
101        }
102    }
103}
104
105impl Display for Expression {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        for token in &self.tokens {
108            write!(f, "{} ", token)?;
109        }
110
111        Ok(())
112    }
113}
114
115#[derive(Debug, PartialEq, Eq, Clone)]
116/// A definition has a "high" and a "low" side. Pink tries to lower the definitions.
117///
118/// It is defined as `high => low`, so expressions will generally be moved to the right.
119pub struct Definition {
120    low: Vec<PatternToken>,
121    high: Vec<PatternToken>,
122}
123
124impl Definition {
125    /// Definitions are defined as `high => low` (so `rhs` is `low` and `lhs` is `high`)
126    pub fn new(lhs: Vec<PatternToken>, rhs: Vec<PatternToken>) -> Self {
127        Self {
128            high: lhs,
129            low: rhs,
130        }
131    }
132
133    /// Transform an expression from one pattern to another.
134    fn transform<'a>(
135        from: &[PatternToken],
136        to: &[PatternToken],
137        expression: &'a [Token],
138    ) -> Option<Expression> {
139        let (single_bindings, spread_bindings) = get_match_bindings(from, expression)?;
140
141        let mut result = Vec::new();
142
143        for token in to {
144            match token {
145                PatternToken::Concrete(token) => result.push(token.clone()),
146                PatternToken::Variable(name) => {
147                    let binding = *single_bindings.get(name)?;
148                    result.push(binding.clone());
149                }
150                PatternToken::SpreadVariable(name) => {
151                    let binding = spread_bindings.get(name)?;
152                    result.extend_from_slice(binding);
153                }
154            };
155        }
156
157        Some(Expression::new(result))
158    }
159
160    pub fn lower(&self, expression: &[Token]) -> Option<Expression> {
161        Self::transform(&self.high, &self.low, expression)
162    }
163
164    pub fn raise(&self, expression: &[Token]) -> Option<Expression> {
165        Self::transform(&self.low, &self.high, expression)
166    }
167}
168
169impl Display for Definition {
170    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171        for token in &self.high {
172            write!(f, "{} ", token)?;
173        }
174
175        write!(f, "=> ")?;
176
177        for token in &self.low {
178            write!(f, "{} ", token)?;
179        }
180
181        Ok(())
182    }
183}
184
185#[derive(Debug, PartialEq, Eq, Clone)]
186pub struct Structure {
187    domain: BTreeSet<String>,
188    reserved: BTreeSet<String>,
189    definitions: Vec<Definition>,
190}
191
192impl Structure {
193    /// Create a new structure.
194    ///
195    /// It is not called `new` because it can fail and using `new` with `Result` is confusing.
196    pub fn create(
197        domain: BTreeSet<String>,
198        reserved: BTreeSet<String>,
199        definitions: Vec<Definition>,
200    ) -> Result<Self, StructureError> {
201        if let Some(culprit) = domain.iter().find(|d| reserved.contains(*d)) {
202            return Err(StructureError::DomainAndReservedOverlap {
203                culprit: culprit.to_owned(),
204            });
205        }
206
207        Ok(Self {
208            domain,
209            reserved,
210            definitions,
211        })
212    }
213
214    /// The "intrinsic" structure is defined by the language itself
215    ///
216    /// It reserves curly braces, parentheses, and commas.
217    pub fn intrinsic() -> Self {
218        let reserved = BTreeSet::from(["{", "}", ",", "(", ")", "="].map(|s| s.to_owned()));
219
220        Structure {
221            domain: BTreeSet::new(),
222            reserved,
223            definitions: Vec::new(),
224        }
225    }
226
227    /// Creates an empty structure
228    pub fn empty() -> Self {
229        Structure {
230            domain: BTreeSet::new(),
231            reserved: BTreeSet::new(),
232            definitions: Vec::new(),
233        }
234    }
235
236    pub fn get_reserved(&self) -> &BTreeSet<String> {
237        &self.reserved
238    }
239
240    pub fn get_domain(&self) -> &BTreeSet<String> {
241        &self.domain
242    }
243}
244
245impl Display for Structure {
246    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
247        let domain: Vec<_> = self.domain.iter().cloned().collect();
248        writeln!(f, "Domain: {{ {} }}", domain.join(", "))?;
249
250        let reserved: Vec<_> = self.reserved.iter().cloned().collect();
251        writeln!(f, "Reserved: {{ {} }}", reserved.join(", "))?;
252
253        writeln!(f, "Definitions: ")?;
254
255        for definition in &self.definitions {
256            writeln!(f, "- {definition};")?;
257        }
258
259        Ok(())
260    }
261}
262
263// I don't know to what extent this error is necessary. Maybe replace it with `Option`?
264#[derive(Debug, PartialEq, Eq)]
265pub enum StructureError {
266    DomainAndReservedOverlap { culprit: String },
267}
268
269impl Display for StructureError {
270    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271        match self {
272            StructureError::DomainAndReservedOverlap { culprit } => {
273                write!(
274                    f,
275                    "Domain and reserved keywords overlap (\"{}\" appears in both)",
276                    culprit
277                )
278            }
279        }
280    }
281}
282
283impl Error for StructureError {}
284
285#[derive(Debug, Clone, PartialEq, Eq)]
286pub struct Runtime {
287    pub structures: BTreeMap<String, Structure>,
288}
289
290impl Runtime {
291    pub fn new(structures: BTreeMap<String, Structure>) -> Self {
292        Self { structures }
293    }
294
295    /// Iterator that goes through each element in the domains of the structures of the runtime
296    pub fn domain(&self) -> impl Iterator<Item = &String> + '_ {
297        self.structures
298            .iter()
299            .flat_map(|(_name, structure)| structure.domain.iter())
300    }
301
302    /// Iterator that goes through each literal in the reserved keywords of the structures of the runtime
303    pub fn reserved(&self) -> impl Iterator<Item = &String> + '_ {
304        self.structures
305            .iter()
306            .flat_map(|(_name, structure)| structure.reserved.iter())
307    }
308
309    /// Iterator that goes through each literal in the reserved keywords of the structures of the runtime
310    pub fn definitions(&self) -> impl Iterator<Item = &Definition> + '_ {
311        self.structures
312            .iter()
313            .flat_map(|(_name, structure)| structure.definitions.iter())
314    }
315
316    pub fn contains(&self, name: &str) -> bool {
317        self.structures.contains_key(name)
318    }
319
320    pub fn insert(&mut self, name: String, structure: Structure) -> Option<Structure> {
321        self.structures.insert(name, structure)
322    }
323
324    pub fn from_partial(structures: &BTreeMap<String, Option<Structure>>) -> Self {
325        let mut runtime = Runtime::new(BTreeMap::new());
326
327        for (name, structure) in structures {
328            if let Some(structure) = structure {
329                runtime.insert(name.to_owned(), structure.to_owned());
330            }
331        }
332
333        runtime
334    }
335
336    pub fn parse_expression(&self, expression: &str) -> Result<Expression, ParseError> {
337        parser::expression(expression, self)
338    }
339}
340
341impl Display for Runtime {
342    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
343        for (name, structure) in &self.structures {
344            writeln!(f, "{name}:")?;
345            writeln!(f, "{structure}")?;
346        }
347
348        Ok(())
349    }
350}