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, supertraits = Sized)]
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, supertraits = Sorts + Sized)]
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}