Skip to main content

alux_shape/
program.rs

1//! A shape stated as a declaration.
2//!
3//! A declaration becomes a program: a value that answers with a shape once an algebra is handed to
4//! it. The backend that lowers one rewrites every `self` in the body to the algebra, so a declaration
5//! reaches its primitives and its members through the same receiver — which is why the operations
6//! below are extensions over the algebra rather than methods on a builder of their own.
7
8use crate::{FieldAlg, ShapeAlg, ShapeExt, Sorts, Words};
9use alux_ext::ext;
10
11/// States the shape a declaration denotes, once an algebra interprets it.
12pub trait ShapeProgramAlg<Alg> {
13    /// The shape the algebra builds.
14    type Ty;
15
16    /// Folds this declaration with the algebra.
17    fn compile_shape(self, alg: &Alg) -> Self::Ty;
18}
19
20/// Compiles a shape declaration with an interpretation.
21#[ext(name = ShapeProgramExt)]
22pub impl<This> This {
23    /// Folds a declaration with this interpretation.
24    fn compile_shape<Program>(&self, program: Program) -> Program::Ty
25    where
26        Program: ShapeProgramAlg<This>,
27    {
28        program.compile_shape(self)
29    }
30}
31
32/// The operations a declaration's body states.
33#[ext(name = ShapeDeclareExt)]
34pub impl<This> This
35where
36    This: ShapeAlg + FieldAlg,
37{
38    /// Opens the product a declaration states, under the name the declaration carries.
39    fn record<'a>(&'a self, words: Words<'a>) -> Record<'a, Self> {
40        Record { alg: self, words, members: Vec::new() }
41    }
42
43    /// The shape another declaration states, folded here.
44    fn program<Program>(&self, program: Program) -> Self::Ty
45    where
46        Program: ShapeProgramAlg<Self, Ty = Self::Ty>,
47    {
48        program.compile_shape(self)
49    }
50}
51
52/// A product being stated, holding the algebra it is stated against.
53///
54/// Not part of this specification: it exists between what a backend reads and what it writes, so it
55/// needs no sort, no primitive, and no mention in the algebra. Members are built as they arrive,
56/// since a declaration has the algebra in hand from its first call.
57pub struct Record<'a, A>
58where
59    A: Sorts,
60{
61    alg: &'a A,
62    words: Words<'a>,
63    members: Vec<A::Field>,
64}
65
66impl<'a, A> Record<'a, A>
67where
68    A: ShapeAlg + FieldAlg,
69{
70    /// States one member, under the name it is written with.
71    #[must_use]
72    pub fn field(mut self, words: Words<'_>, shape: A::Ty) -> Self {
73        self.members.push(self.alg.field(words, shape));
74
75        self
76    }
77
78    /// States one member, and the type a layout carries it in.
79    ///
80    /// The type is the layout's business and not this one's: nothing here reads it, and an expansion
81    /// emits a field of that type. A declaration writes `field::<Carrier>(name, shape)`, which lowers
82    /// to this.
83    #[must_use]
84    pub fn field_as<Carrier>(mut self, words: Words<'_>, shape: A::Ty) -> Self {
85        self.members.push(self.alg.field(words, shape));
86
87        self
88    }
89
90    /// States one member whose shape its own type states.
91    ///
92    /// Available where a type says what it is — a layout with a shape of its own, or a leaf whose
93    /// domain states one. A name that is only an alias states what the type it names states, so a
94    /// member wanting a name of its own gives its shape instead.
95    #[must_use]
96    pub fn field_of<Carrier>(mut self, words: Words<'_>) -> Self
97    where
98        Carrier: crate::ShapeOf<A, Shape = A::Ty>,
99    {
100        let shape = Carrier::shape_of(self.alg);
101        self.members.push(self.alg.field(words, shape));
102
103        self
104    }
105
106    /// States another product's members as this one's own.
107    #[must_use]
108    pub fn merge(mut self, shape: A::Ty) -> Self {
109        self.members.push(self.alg.merge(shape));
110
111        self
112    }
113
114    /// Answers with the shape this product states.
115    #[must_use]
116    pub fn into_shape(self) -> A::Ty {
117        self.alg.named_product(self.words, self.members)
118    }
119}