catlog/tt/
stx.rs

1//! Syntax for types and terms.
2//!
3//! See [crate::tt] for what this means.
4
5use derive_more::{Constructor, Deref};
6use std::fmt;
7use std::fmt::Write as _;
8
9use super::{prelude::*, theory::*};
10use crate::zero::LabelSegment;
11
12/// A metavariable.
13///
14/// Metavariables are emitted on elaboration error or when explicitly
15/// requested with `@hole`.
16///
17/// Metavariables in notebook elaboration are namespaced to the notebook.
18#[derive(Constructor, Clone, Copy, PartialEq, Eq)]
19pub struct MetaVar {
20    ref_id: Option<Ustr>,
21    id: usize,
22}
23
24impl fmt::Display for MetaVar {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        write!(f, "?{}", self.id)
27    }
28}
29
30/// Inner enum for [BaseTyS].
31pub enum BaseTyS_ {
32    /// A reference to a top-level declaration.
33    TopVar(TopVarName),
34    /// Type constructor for object types.
35    ///
36    /// Example syntax: `Entity` (top-level constants are bound by the elaborator to
37    /// various object types).
38    ///
39    /// A term of type `Object(ot)` represents an object of object type `ot`.
40    Object(ObType),
41
42    /// Type constructor for morphism types.
43    ///
44    /// Example syntax: `Attr x a` (top-level constants are bound by the elaborator
45    /// to constructors for morphism types).
46    ///
47    /// A term of type `Morphism(mt, dom, cod)` represents an morphism of morphism
48    /// type `mt` from `dom` to `cod`.
49    Morphism(MorType, BaseTmS, BaseTmS),
50
51    /// Type constructor for record types.
52    ///
53    /// Example syntax: `[x : A, y : B]`.
54    ///
55    /// A term `x` of type `Record(r)` represents a record where field `f` has type
56    /// `eval(env.snoc(eval(env, x)), r.fields1[f])`.
57    Record(Row<BaseTyS>),
58
59    /// Type constructor for singleton types.
60    ///
61    /// Example syntax: `@sing a` (assuming `a` is a term that synthesizes a type).
62    ///
63    /// A term `x` of type `Sing(ty, tm)` is a term of `ty` that is convertible with
64    /// `tm`.
65    Sing(BaseTyS, BaseTmS),
66
67    /// Type constructor for identity types.
68    ///
69    /// Example syntax: `a == b` (assuming `a` and `b` are terms that synthesize the same type).
70    ///
71    /// A term `p` of type `a == b` is a proof that `a` and `b` are equal.
72    Id(BaseTyS, BaseTmS, BaseTmS),
73
74    /// Type constructor for specialized types.
75    ///
76    /// Example syntax: `A & [ .x : @sing a ]`.
77    ///
78    /// A term `x` of type `Specialize(ty, d)` is a term of `ty` where additionally
79    /// for each path `p` (e.g. `.x`, `.a.b`, etc.) in `d`, `x.p` is of type `d[p]`.
80    ///
81    /// In order to form this type, it must be the case that `d[p]` is a subtype of
82    /// the type of the field at path `p`.
83    Specialize(BaseTyS, Vec<(Vec<(FieldName, LabelSegment)>, BaseTyS)>),
84
85    /// A metavar.
86    ///
87    /// Currently, this is only used for handling elaboration errors, we might
88    /// add more unification/holes later.
89    Meta(MetaVar),
90}
91
92/// Syntax for total types, dereferences to [BaseTyS_].
93///
94/// See [crate::tt] for an explanation of what total types are, and for an
95/// explanation of our approach to Rc pointers in abstract syntax trees.
96#[derive(Clone, Deref)]
97#[deref(forward)]
98pub struct BaseTyS(Rc<BaseTyS_>);
99
100impl BaseTyS {
101    /// Smart constructor for [BaseTyS], [BaseTyS_::TopVar] case.
102    pub fn topvar(name: TopVarName) -> Self {
103        Self(Rc::new(BaseTyS_::TopVar(name)))
104    }
105
106    /// Smart constructor for [BaseTyS], [BaseTyS_::Object] case.
107    pub fn object(object_type: ObType) -> Self {
108        Self(Rc::new(BaseTyS_::Object(object_type)))
109    }
110
111    /// Smart constructor for [BaseTyS], [BaseTyS_::Morphism] case.
112    pub fn morphism(morphism_type: MorType, dom: BaseTmS, cod: BaseTmS) -> Self {
113        Self(Rc::new(BaseTyS_::Morphism(morphism_type, dom, cod)))
114    }
115
116    /// Smart constructor for [BaseTyS], [BaseTyS_::Record] case.
117    pub fn record(fields: Row<BaseTyS>) -> Self {
118        Self(Rc::new(BaseTyS_::Record(fields)))
119    }
120
121    /// Smart constructor for [BaseTyS], [BaseTyS_::Sing] case.
122    pub fn sing(ty: BaseTyS, tm: BaseTmS) -> Self {
123        Self(Rc::new(BaseTyS_::Sing(ty, tm)))
124    }
125
126    /// Smart constructor for [BaseTyS], [BaseTyS_::Id] case.
127    pub fn id(ty: BaseTyS, tm1: BaseTmS, tm2: BaseTmS) -> Self {
128        Self(Rc::new(BaseTyS_::Id(ty, tm1, tm2)))
129    }
130
131    /// Smart constructor for [BaseTyS], [BaseTyS_::Specialize] case.
132    pub fn specialize(
133        ty: BaseTyS,
134        specializations: Vec<(Vec<(FieldName, LabelSegment)>, BaseTyS)>,
135    ) -> Self {
136        Self(Rc::new(BaseTyS_::Specialize(ty, specializations)))
137    }
138
139    /// Smart constructor for [BaseTyS], [BaseTyS_::Meta] case.
140    pub fn meta(mv: MetaVar) -> Self {
141        Self(Rc::new(BaseTyS_::Meta(mv)))
142    }
143}
144
145impl ToDoc for BaseTyS {
146    fn to_doc<'a>(&self) -> D<'a> {
147        match &**self {
148            BaseTyS_::TopVar(name) => t(format!("{}", name)),
149            BaseTyS_::Object(ob_type) => t(format!("{}", ob_type)),
150            BaseTyS_::Morphism(mor_type, dom, cod) => {
151                mor_type.to_doc().parens() + tuple([dom.to_doc(), cod.to_doc()])
152            }
153            BaseTyS_::Record(fields) => tuple(fields.iter().map(|(_, (label, ty))| {
154                binop(t(":"), t(format!("{}", label)).group(), ty.to_doc())
155            })),
156            BaseTyS_::Sing(_, tm) => t("@sing") + s() + tm.to_doc(),
157            BaseTyS_::Id(_, tm1, tm2) => binop(t("=="), tm1.to_doc(), tm2.to_doc()),
158            BaseTyS_::Specialize(ty, d) => binop(
159                t("&"),
160                ty.to_doc(),
161                tuple(
162                    d.iter().map(|(name, ty)| binop(t(":"), t(path_to_string(name)), ty.to_doc())),
163                ),
164            ),
165            BaseTyS_::Meta(mv) => t(format!("?{}", mv.id)),
166        }
167    }
168}
169
170fn path_to_string(path: &[(FieldName, LabelSegment)]) -> String {
171    let mut out = String::new();
172    for (_, seg) in path {
173        write!(&mut out, ".{}", seg).unwrap();
174    }
175    out
176}
177
178impl fmt::Display for BaseTyS {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180        write!(f, "{}", self.to_doc().group().pretty())
181    }
182}
183
184/// Inner enum for [BaseTmS].
185pub enum BaseTmS_ {
186    /// An application of a top-level term judgment to arguments.
187    ///
188    /// A closed term (a nullary `def`, e.g. `tt : Unit`) is the empty-argument
189    /// case `TopApp(name, [])`.
190    TopApp(TopVarName, Vec<BaseTmS>),
191    /// Variable syntax.
192    ///
193    /// We use a backward index, as when we evaluate we store the
194    /// environment in a [bwd::Bwd], and this indexes into that.
195    Var(BwdIdx, VarName, LabelSegment),
196    /// Record introduction.
197    Cons(Row<BaseTmS>),
198    /// Record elimination.
199    Proj(BaseTmS, FieldName, LabelSegment),
200    /// Identity morphism at an object.
201    Id(BaseTmS),
202    /// Tabulation of a morphism.
203    Tab(BaseTmS),
204    /// Composite of two morphisms.
205    Compose(BaseTmS, BaseTmS),
206    /// Application of an object operation in the theory.
207    ObApp(VarName, BaseTmS),
208    /// List of objects.
209    List(Vec<BaseTmS>),
210    /// A metavar.
211    ///
212    /// This only appears when we have an error in elaboration.
213    Meta(MetaVar),
214}
215
216/// Syntax for total terms, dereferences to [BaseTmS_].
217///
218/// See [crate::tt] for an explanation of what total types are, and for an
219/// explanation of our approach to Rc pointers in abstract syntax trees.
220#[derive(Clone, Deref)]
221#[deref(forward)]
222pub struct BaseTmS(Rc<BaseTmS_>);
223
224impl BaseTmS {
225    /// Smart constructor for [BaseTmS], [BaseTmS_::TopApp] case.
226    pub fn topapp(var_name: VarName, args: Vec<BaseTmS>) -> Self {
227        Self(Rc::new(BaseTmS_::TopApp(var_name, args)))
228    }
229
230    /// Smart constructor for [BaseTmS], [BaseTmS_::Var] case.
231    pub fn var(bwd_idx: BwdIdx, var_name: VarName, label: LabelSegment) -> Self {
232        Self(Rc::new(BaseTmS_::Var(bwd_idx, var_name, label)))
233    }
234
235    /// Smart constructor for [BaseTmS], [BaseTmS_::Cons] case.
236    pub fn cons(row: Row<BaseTmS>) -> Self {
237        Self(Rc::new(BaseTmS_::Cons(row)))
238    }
239
240    /// Smart constructor for [BaseTmS], [BaseTmS_::Proj] case.
241    pub fn proj(tm_s: BaseTmS, field_name: FieldName, label: LabelSegment) -> Self {
242        Self(Rc::new(BaseTmS_::Proj(tm_s, field_name, label)))
243    }
244
245    /// Smart constructor for [BaseTmS], [BaseTmS_::Id] case.
246    pub fn id(ob: BaseTmS) -> Self {
247        Self(Rc::new(BaseTmS_::Id(ob)))
248    }
249
250    /// Smart constructor for [BaseTmS], [BaseTmS_::Tab] case.
251    pub fn tab(mor: BaseTmS) -> Self {
252        Self(Rc::new(BaseTmS_::Tab(mor)))
253    }
254
255    /// Smart constructor for [BaseTmS], [BaseTmS_::Compose] case.
256    pub fn compose(f: BaseTmS, g: BaseTmS) -> Self {
257        Self(Rc::new(BaseTmS_::Compose(f, g)))
258    }
259
260    /// Smart constructor for [BaseTmS], [BaseTmS_::ObApp] case.
261    pub fn ob_app(name: VarName, x: BaseTmS) -> Self {
262        Self(Rc::new(BaseTmS_::ObApp(name, x)))
263    }
264
265    /// Smart constructor for [BaseTmS], [BaseTmS_::List] case.
266    pub fn list(elems: Vec<BaseTmS>) -> Self {
267        Self(Rc::new(BaseTmS_::List(elems)))
268    }
269
270    /// Smart constructor for [BaseTmS], [BaseTmS_::Meta] case.
271    pub fn meta(mv: MetaVar) -> Self {
272        Self(Rc::new(BaseTmS_::Meta(mv)))
273    }
274}
275
276impl ToDoc for BaseTmS {
277    fn to_doc<'a>(&self) -> D<'a> {
278        match &**self {
279            BaseTmS_::TopApp(name, args) if args.is_empty() => t(format!("{}", name)),
280            BaseTmS_::TopApp(name, args) => {
281                t(format!("{}", name)) + tuple(args.iter().map(|arg| arg.to_doc()))
282            }
283            BaseTmS_::Var(_, _, label) => t(format!("{}", label)),
284            BaseTmS_::Proj(tm, _, label) => tm.to_doc() + t(format!(".{}", label)),
285            BaseTmS_::Cons(fields) => tuple(fields.iter().map(|(_, (label, field))| {
286                binop(t(":="), t(format!("{}", label)), field.to_doc())
287            })),
288            BaseTmS_::Id(ob) => (t("@id") + s() + ob.to_doc()).parens(),
289            BaseTmS_::Tab(mor) => (t("@tab") + s() + mor.to_doc()).parens(),
290            BaseTmS_::Compose(f, g) => binop(t("·"), f.to_doc(), g.to_doc()),
291            BaseTmS_::ObApp(name, x) => unop(t(format!("@{name}")), x.to_doc()),
292            BaseTmS_::List(elems) => tuple(elems.iter().map(|elem| elem.to_doc())),
293            BaseTmS_::Meta(mv) => t(format!("?{}", mv.id)),
294        }
295    }
296}
297
298impl fmt::Display for BaseTmS {
299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300        write!(f, "{}", self.to_doc().group().pretty())
301    }
302}
303
304/// Inner enum for [FiberTyS].
305///
306/// Fiber types type the fiber world — instances of a model and their
307/// elements — mirroring how [`BaseTyS`] types the base world (models).
308/// See [`crate::tt::toplevel`] for the comprehension-category picture.
309/// The constructors parallel the base world: [`TopVar`](Self::TopVar)
310/// references a top-level instance, [`Over`](Self::Over) is the atomic
311/// fiber-element type, [`Record`](Self::Record) assembles them into an
312/// instance, and [`Id`](Self::Id) imposes a (propositional) equation —
313/// just as [`BaseTyS_::TopVar`] and [`BaseTyS_::Id`] do in the base.
314pub enum FiberTyS_ {
315    /// A reference to a top-level instance declaration, as in a
316    /// sub-instance import `we : Edge`. Mirrors [`BaseTyS_::TopVar`]: it
317    /// appears only in *syntax* and exists to preserve the instance's
318    /// name for display — like base top-vars, it is resolved away in the
319    /// value world (there is no `FiberTyV_::TopVar`), where it becomes the
320    /// referenced instance's [`Record`](Self::Record).
321    TopVar(TopVarName),
322    /// The type of a fiber element lying over a codomain object `obj`.
323    ///
324    /// `obj` is a base object *term* (rooted at the codomain model), so it
325    /// may be a plain generator (`self.V`), or a modal object such as a
326    /// list `[M, M]` or a tensor `@tensor [H, M]`. Comparing two
327    /// `Over` types is comparing their base objects, so modal objects need
328    /// no special handling. No surface syntax — its inhabitants
329    /// ([`FiberTmS`]) are introduced by set-literal clauses `field :=
330    /// [...]`, projection out of a sub-instance import, fiber list/object
331    /// -operation literals, and codomain-morphism application.
332    Over(BaseTmS),
333    /// An instance of a model — an object of the fiber over the codomain
334    /// model — presented as a record of fiber types. A generator is an
335    /// [`Over`](Self::Over) field, a sub-instance import is a nested
336    /// [`Record`](Self::Record) field, and an equation is an
337    /// [`Id`](Self::Id) field. This is what `instance I : X := [...]`
338    /// elaborates to, and also the type of a sub-instance import `we :
339    /// Edge` (whose generators are then projected as `we.e`).
340    Record(Row<FiberTyS>),
341    /// A propositional equation between two fiber elements of the given
342    /// fiber type, asserted to hold in the enclosing instance. Mirrors
343    /// [`BaseTyS_::Id`]; like it, these are proof-irrelevant.
344    Id(FiberTyS, FiberTmS, FiberTmS),
345}
346
347/// Syntax for fiber types, dereferences to [FiberTyS_].
348#[derive(Clone, Deref)]
349#[deref(forward)]
350pub struct FiberTyS(Rc<FiberTyS_>);
351
352impl FiberTyS {
353    /// Smart constructor for [FiberTyS], [FiberTyS_::TopVar] case.
354    pub fn topvar(name: TopVarName) -> Self {
355        Self(Rc::new(FiberTyS_::TopVar(name)))
356    }
357
358    /// Smart constructor for [FiberTyS], [FiberTyS_::Over] case.
359    pub fn over(obj: BaseTmS) -> Self {
360        Self(Rc::new(FiberTyS_::Over(obj)))
361    }
362
363    /// Smart constructor for [FiberTyS], [FiberTyS_::Record] case.
364    pub fn record(fields: Row<FiberTyS>) -> Self {
365        Self(Rc::new(FiberTyS_::Record(fields)))
366    }
367
368    /// Smart constructor for [FiberTyS], [FiberTyS_::Id] case.
369    pub fn id(ty: FiberTyS, tm1: FiberTmS, tm2: FiberTmS) -> Self {
370        Self(Rc::new(FiberTyS_::Id(ty, tm1, tm2)))
371    }
372}
373
374impl ToDoc for FiberTyS {
375    fn to_doc<'a>(&self) -> D<'a> {
376        match &**self {
377            FiberTyS_::TopVar(name) => t(format!("{}", name)),
378            FiberTyS_::Over(obj) => t("Over(") + obj.to_doc() + t(")"),
379            FiberTyS_::Record(fields) => tuple(fields.iter().map(|(_, (label, ty))| {
380                binop(t(":"), t(format!("{}", label)).group(), ty.to_doc())
381            })),
382            FiberTyS_::Id(_, tm1, tm2) => binop(t("=="), tm1.to_doc(), tm2.to_doc()),
383        }
384    }
385}
386
387impl fmt::Display for FiberTyS {
388    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389        write!(f, "{}", self.to_doc().group().pretty())
390    }
391}
392
393/// Inner enum for [FiberTmS]: a term of a fiber type, i.e. an element of
394/// an instance.
395///
396/// Fiber terms reference the elaborator's *fiber* scope (generators and
397/// sub-instance imports), which is separate from the base context; see
398/// [`crate::tt::context::Context`]. They are all neutral — there is no
399/// fiber introduction form yet (mapping out of an instance by a record
400/// literal is future work), so a fiber term is always a variable, a
401/// projection, or a codomain-morphism application.
402pub enum FiberTmS_ {
403    /// A fiber-context variable: a generator or a sub-instance import.
404    /// Backward index into the fiber environment.
405    Var(BwdIdx, VarName, LabelSegment),
406    /// Projection of a generator out of a sub-instance import, e.g.
407    /// `we.e`.
408    Proj(FiberTmS, FieldName, LabelSegment),
409    /// A fiber list literal `[a, b, ...]` (possibly empty). Its fiber type
410    /// is `Over([A, B, ...])` where each `x_i : Over(A_i)`. Mirrors base
411    /// [`BaseTmS_::List`]; used to supply the (modal) list argument of a
412    /// multi-ary morphism, e.g. `op[x, x]`.
413    List(Vec<FiberTmS>),
414    /// Application of a theory object-operation to a fiber element, e.g.
415    /// `@tensor [a, b]`. Mirrors base [`BaseTmS_::ObApp`]; its fiber type
416    /// is `Over(@op ...)` over the operation applied to the argument's
417    /// base object.
418    ObApp(VarName, FiberTmS),
419    /// Application of a codomain morphism to a fiber element. Arguments,
420    /// in order: the *path* to the morphism in the codomain (a single
421    /// segment like `src`, or a nested one like `Add.op` for a morphism of
422    /// a sub-model), the codomain object it lands at (a base object term,
423    /// stored so the result fiber type is recoverable without re-deriving
424    /// it), and the fiber-typed argument (e.g. the elaboration of `we.e`,
425    /// or a fiber list `[x, x]` for a multi-ary morphism).
426    ///
427    /// Example: in `src(we.e) := v1`, the LHS elaborates to
428    /// `OverApp([src], self.V, Proj(Var(we), e, e))` of fiber type
429    /// `Over(self.V)`.
430    OverApp(Vec<(FieldName, LabelSegment)>, BaseTmS, FiberTmS),
431    /// A metavar (elaboration-error placeholder).
432    Meta(MetaVar),
433}
434
435/// Syntax for fiber terms, dereferences to [FiberTmS_].
436#[derive(Clone, Deref)]
437#[deref(forward)]
438pub struct FiberTmS(Rc<FiberTmS_>);
439
440impl FiberTmS {
441    /// Smart constructor for [FiberTmS], [FiberTmS_::Var] case.
442    pub fn var(bwd_idx: BwdIdx, var_name: VarName, label: LabelSegment) -> Self {
443        Self(Rc::new(FiberTmS_::Var(bwd_idx, var_name, label)))
444    }
445
446    /// Smart constructor for [FiberTmS], [FiberTmS_::Proj] case.
447    pub fn proj(tm: FiberTmS, field_name: FieldName, label: LabelSegment) -> Self {
448        Self(Rc::new(FiberTmS_::Proj(tm, field_name, label)))
449    }
450
451    /// Smart constructor for [FiberTmS], [FiberTmS_::List] case.
452    pub fn list(elems: Vec<FiberTmS>) -> Self {
453        Self(Rc::new(FiberTmS_::List(elems)))
454    }
455
456    /// Smart constructor for [FiberTmS], [FiberTmS_::ObApp] case.
457    pub fn ob_app(name: VarName, arg: FiberTmS) -> Self {
458        Self(Rc::new(FiberTmS_::ObApp(name, arg)))
459    }
460
461    /// Smart constructor for [FiberTmS], [FiberTmS_::OverApp] case.
462    pub fn over_app(mor: Vec<(FieldName, LabelSegment)>, cod: BaseTmS, inner: FiberTmS) -> Self {
463        Self(Rc::new(FiberTmS_::OverApp(mor, cod, inner)))
464    }
465
466    /// Smart constructor for [FiberTmS], [FiberTmS_::Meta] case.
467    pub fn meta(mv: MetaVar) -> Self {
468        Self(Rc::new(FiberTmS_::Meta(mv)))
469    }
470}
471
472impl ToDoc for FiberTmS {
473    fn to_doc<'a>(&self) -> D<'a> {
474        match &**self {
475            FiberTmS_::Var(_, _, label) => t(format!("{}", label)),
476            FiberTmS_::Proj(tm, _, label) => tm.to_doc() + t(format!(".{}", label)),
477            FiberTmS_::List(elems) => tuple(elems.iter().map(|e| e.to_doc())),
478            FiberTmS_::ObApp(name, arg) => unop(t(format!("@{name}")), arg.to_doc()),
479            FiberTmS_::OverApp(path, _, inner) => {
480                let mut d = inner.to_doc();
481                for (_, label) in path {
482                    d = d + t(format!(".{label}"));
483                }
484                d
485            }
486            FiberTmS_::Meta(mv) => t(format!("?{}", mv.id)),
487        }
488    }
489}
490
491impl fmt::Display for FiberTmS {
492    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493        write!(f, "{}", self.to_doc().group().pretty())
494    }
495}