Skip to main content

alux_shape_term/
term.rs

1//! A shape term as a value, so that a term can be written down and read back.
2//!
3//! Every other interpretation answers with something that is not a shape — text, a judgement, a
4//! declaration. This one answers with the term itself, which is what lets a shape leave the host
5//! that stated it: written here, read there, and folded into whichever algebra that host carries.
6
7use alux_shape::{FieldAlg, ShapeAlg, Sorts, Words};
8use serde::{Deserialize, Serialize};
9
10/// A shape, as a value.
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "camelCase")]
13pub enum Term {
14    Truth,
15    Unit,
16    Text,
17    Literal(String),
18    NameWord(Vec<String>),
19    Int { signed: bool, bits: u16 },
20    Float { bits: u16 },
21    Bytes { len: Option<usize> },
22    Hex(Box<Term>),
23    Decimal(Box<Term>),
24    Base64(Box<Term>),
25    Opt(Box<Term>),
26    Seq(Box<Term>),
27    Map(Box<Term>, Box<Term>),
28    Product(Vec<Member>),
29    Choice(Vec<Term>),
30    Named { words: Vec<String>, body: Box<Term> },
31    Reference(Vec<String>),
32}
33
34/// One member of a product, as a value.
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub enum Member {
38    /// A member under the name it is written with.
39    Field { words: Vec<String>, shape: Term },
40    /// Another product's members, observed as this product's own.
41    Merge(Term),
42}
43
44/// Borrows a name's words in the form the algebra states them.
45fn borrow(words: &[String]) -> Vec<&str> {
46    words.iter().map(String::as_str).collect()
47}
48
49/// Owns a name's words, to keep them in a term.
50fn own(words: Words<'_>) -> Vec<String> {
51    words.iter().map(|word| (*word).to_owned()).collect()
52}
53
54impl Term {
55    /// Folds this term into whichever algebra an interpretation provides.
56    ///
57    /// This is the reader: a term written by one host is interpreted by another without either
58    /// naming the other's types. Reading and writing are checked against each other, since folding a
59    /// written term with any interpretation answers what interpreting the original directly does.
60    pub fn fold<A>(&self, alg: &A) -> A::Ty
61    where
62        A: ShapeAlg + FieldAlg,
63    {
64        match self {
65            Self::Truth => alg.truth(),
66            Self::Unit => alg.unit(),
67            Self::Text => alg.text(),
68            Self::Literal(text) => alg.literal(text),
69            Self::NameWord(words) => alg.name_word(&borrow(words)),
70            Self::Int { signed, bits } => alg.int(*signed, *bits),
71            Self::Float { bits } => alg.float(*bits),
72            Self::Bytes { len } => alg.bytes(*len),
73            Self::Hex(item) => alg.hex(item.fold(alg)),
74            Self::Decimal(item) => alg.decimal(item.fold(alg)),
75            Self::Base64(item) => alg.base64(item.fold(alg)),
76            Self::Opt(item) => alg.opt(item.fold(alg)),
77            Self::Seq(item) => alg.seq(item.fold(alg)),
78            Self::Map(key, value) => alg.map(key.fold(alg), value.fold(alg)),
79            Self::Product(members) => alg.product(members.iter().map(|member| member.fold(alg)).collect()),
80            Self::Choice(alternatives) => alg.choice(alternatives.iter().map(|item| item.fold(alg)).collect()),
81            Self::Named { words, body } => alg.named(&borrow(words), body.fold(alg)),
82            Self::Reference(words) => alg.reference(&borrow(words)),
83        }
84    }
85
86    /// Answers with this term, with every reference replaced by the shape its name introduces.
87    ///
88    /// A fold cannot do this: it builds from the leaves upward, so a reference reaches it before the
89    /// name it uses has been seen. A term holds the whole shape at once, which is what makes a name
90    /// resolvable — and is why an interpretation that must decide a value, rather than describe one,
91    /// reads a resolved term.
92    ///
93    /// A name that would resolve into itself is left as a reference, since expanding it never ends.
94    #[must_use]
95    pub fn resolved(&self) -> Self {
96        let mut definitions = Vec::new();
97        self.definitions(&mut definitions);
98
99        self.expand(&definitions, &mut Vec::new())
100    }
101
102    /// Collects every name this term introduces, with the shape it names.
103    fn definitions<'a>(&'a self, found: &mut Vec<(&'a [String], &'a Self)>) {
104        if let Self::Named { words, body } = self {
105            found.push((words, body));
106        }
107
108        self.children().for_each(|child| child.definitions(found));
109    }
110
111    /// Replaces the references in this term, refusing to expand a name already being expanded.
112    fn expand(&self, definitions: &[(&[String], &Self)], expanding: &mut Vec<Vec<String>>) -> Self {
113        match self {
114            Self::Reference(words) => {
115                let known = definitions.iter().find(|(name, _)| *name == words.as_slice());
116
117                match known {
118                    Some((_, body)) if !expanding.iter().any(|name| name == words) => {
119                        expanding.push(words.clone());
120                        let expanded = body.expand(definitions, expanding);
121                        expanding.pop();
122
123                        Self::Named { words: words.clone(), body: Box::new(expanded) }
124                    }
125                    _ => self.clone(),
126                }
127            }
128            Self::Hex(item) => Self::Hex(Box::new(item.expand(definitions, expanding))),
129            Self::Decimal(item) => Self::Decimal(Box::new(item.expand(definitions, expanding))),
130            Self::Base64(item) => Self::Base64(Box::new(item.expand(definitions, expanding))),
131            Self::Opt(item) => Self::Opt(Box::new(item.expand(definitions, expanding))),
132            Self::Seq(item) => Self::Seq(Box::new(item.expand(definitions, expanding))),
133            Self::Map(key, value) => {
134                Self::Map(Box::new(key.expand(definitions, expanding)), Box::new(value.expand(definitions, expanding)))
135            }
136            Self::Product(members) => {
137                Self::Product(members.iter().map(|member| member.expand(definitions, expanding)).collect())
138            }
139            Self::Choice(alternatives) => {
140                Self::Choice(alternatives.iter().map(|item| item.expand(definitions, expanding)).collect())
141            }
142            Self::Named { words, body } => {
143                expanding.push(words.clone());
144                let body = body.expand(definitions, expanding);
145                expanding.pop();
146
147                Self::Named { words: words.clone(), body: Box::new(body) }
148            }
149            leaf => leaf.clone(),
150        }
151    }
152
153    /// The terms this one is built from.
154    fn children(&self) -> Box<dyn Iterator<Item = &Self> + '_> {
155        match self {
156            Self::Hex(item)
157            | Self::Decimal(item)
158            | Self::Base64(item)
159            | Self::Opt(item)
160            | Self::Seq(item)
161            | Self::Named { body: item, .. } => Box::new(std::iter::once(&**item)),
162            Self::Map(key, value) => Box::new([&**key, &**value].into_iter()),
163            Self::Product(members) => Box::new(members.iter().map(Member::shape)),
164            Self::Choice(alternatives) => Box::new(alternatives.iter()),
165            _ => Box::new(std::iter::empty()),
166        }
167    }
168}
169
170impl Member {
171    /// The shape this member carries, whether as a member of its own or as a merge.
172    fn shape(&self) -> &Term {
173        match self {
174            Self::Field { shape, .. } | Self::Merge(shape) => shape,
175        }
176    }
177
178    /// Replaces the references in this member.
179    fn expand(&self, definitions: &[(&[String], &Term)], expanding: &mut Vec<Vec<String>>) -> Self {
180        match self {
181            Self::Field { words, shape } => {
182                Self::Field { words: words.clone(), shape: shape.expand(definitions, expanding) }
183            }
184            Self::Merge(shape) => Self::Merge(shape.expand(definitions, expanding)),
185        }
186    }
187
188    /// Folds this member into whichever algebra an interpretation provides.
189    pub fn fold<A>(&self, alg: &A) -> A::Field
190    where
191        A: ShapeAlg + FieldAlg,
192    {
193        match self {
194            Self::Field { words, shape } => alg.field(&borrow(words), shape.fold(alg)),
195            Self::Merge(shape) => alg.merge(shape.fold(alg)),
196        }
197    }
198}
199
200/// Interprets a shape as the term it is.
201#[derive(Debug, Clone, Copy, Default)]
202pub struct TermShape;
203
204impl Sorts for TermShape {
205    type Ty = Term;
206    type Field = Member;
207}
208
209impl ShapeAlg for TermShape {
210    fn truth(&self) -> Term {
211        Term::Truth
212    }
213
214    fn unit(&self) -> Term {
215        Term::Unit
216    }
217
218    fn text(&self) -> Term {
219        Term::Text
220    }
221
222    fn literal(&self, text: &str) -> Term {
223        Term::Literal(text.to_owned())
224    }
225
226    fn name_word(&self, words: Words<'_>) -> Term {
227        Term::NameWord(own(words))
228    }
229
230    fn int(&self, signed: bool, bits: u16) -> Term {
231        Term::Int { signed, bits }
232    }
233
234    fn float(&self, bits: u16) -> Term {
235        Term::Float { bits }
236    }
237
238    fn bytes(&self, len: Option<usize>) -> Term {
239        Term::Bytes { len }
240    }
241
242    fn hex(&self, item: Term) -> Term {
243        Term::Hex(Box::new(item))
244    }
245
246    fn decimal(&self, item: Term) -> Term {
247        Term::Decimal(Box::new(item))
248    }
249
250    fn base64(&self, item: Term) -> Term {
251        Term::Base64(Box::new(item))
252    }
253
254    fn opt(&self, item: Term) -> Term {
255        Term::Opt(Box::new(item))
256    }
257
258    fn seq(&self, item: Term) -> Term {
259        Term::Seq(Box::new(item))
260    }
261
262    fn map(&self, key: Term, value: Term) -> Term {
263        Term::Map(Box::new(key), Box::new(value))
264    }
265
266    fn product(&self, fields: Vec<Member>) -> Term {
267        Term::Product(fields)
268    }
269
270    fn choice(&self, alternatives: Vec<Term>) -> Term {
271        Term::Choice(alternatives)
272    }
273
274    fn named(&self, words: Words<'_>, body: Term) -> Term {
275        Term::Named { words: own(words), body: Box::new(body) }
276    }
277
278    fn reference(&self, words: Words<'_>) -> Term {
279        Term::Reference(own(words))
280    }
281}
282
283impl FieldAlg for TermShape {
284    fn field(&self, words: Words<'_>, shape: Term) -> Member {
285        Member::Field { words: own(words), shape }
286    }
287
288    fn merge(&self, shape: Term) -> Member {
289        Member::Merge(shape)
290    }
291}