catlog/tt/toplevel.rs
1//! Data structures for managing toplevel declarations in the type theory.
2//!
3//! Specifically, notebooks will produce [TopDecl::Type] declarations.
4
5use std::fmt;
6
7use crate::{
8 dbl::theory::DiscreteDblTheory,
9 stdlib::{th_category, th_schema, th_signed_category},
10 tt::{prelude::*, stx::*, val::*},
11 zero::{QualifiedName, name},
12};
13
14/// A theory supported by doublett.
15///
16/// Equality of these theories is nominal; two theories are the same if and only
17/// if they have the same name.
18///
19/// When we add features to doublett, this will become an enum; doublett will
20/// never be parametric (e.g., we will not thread a "theory" type through a bunch
21/// of structs in doublett).
22#[derive(Clone)]
23pub struct Theory {
24 /// The name of the theory.
25 pub name: QualifiedName,
26 /// The definition of the theory.
27 pub definition: Rc<DiscreteDblTheory>,
28}
29
30impl Theory {
31 /// Default constructor for [Theory].
32 pub fn new(name: QualifiedName, definition: Rc<DiscreteDblTheory>) -> Self {
33 Self { name, definition }
34 }
35}
36
37impl PartialEq for Theory {
38 fn eq(&self, other: &Self) -> bool {
39 self.name == other.name
40 }
41}
42
43impl Eq for Theory {}
44
45impl fmt::Display for Theory {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(f, "{}", self.name)
48 }
49}
50
51/// A toplevel declaration.
52#[derive(Clone)]
53pub enum TopDecl {
54 /// See [Type]
55 Type(Type),
56 /// See [DefConst]
57 DefConst(DefConst),
58 /// See [Def]
59 Def(Def),
60}
61
62/// A toplevel declaration of a type.
63///
64/// Also stores the evaluation of that type. Because this is an evaluation in
65/// the empty context, this is OK to use in any other context as well.
66#[derive(Clone)]
67pub struct Type {
68 /// The theory for the type
69 pub theory: Theory,
70 /// The syntax of the type (unnormalized)
71 pub stx: TyS,
72 /// The value of the type (normalized)
73 pub val: TyV,
74}
75
76impl Type {
77 /// Default constructor for [Type]
78 pub fn new(theory: Theory, stx: TyS, val: TyV) -> Self {
79 Self { theory, stx, val }
80 }
81}
82
83/// A toplevel declaration of a term in the empty context.
84///
85/// Also stores the evaluation of that term, and the evaluation of the corresponding type of that term. Because this is an evaluation in the
86/// empty context, this is OK to use in any other context as well.
87#[derive(Clone)]
88pub struct DefConst {
89 /// The theory that the constant is defined in
90 pub theory: Theory,
91 /// The syntax of the constant (unnormalized)
92 pub stx: TmS,
93 /// The value of the constant (normalized)
94 pub val: TmV,
95 /// The type of the constant
96 pub ty: TyV,
97}
98
99impl DefConst {
100 /// Default constructor for [DefConst]
101 pub fn new(theory: Theory, stx: TmS, val: TmV, ty: TyV) -> Self {
102 Self {
103 theory,
104 stx,
105 val,
106 ty,
107 }
108 }
109}
110
111/// A toplevel declaration of a term judgment
112#[derive(Clone)]
113pub struct Def {
114 /// The theory that the definition is defined in
115 pub theory: Theory,
116 /// The arguments for the definition
117 pub args: Row<TyS>,
118 /// The return type of the definition (to be evaluated in an environment
119 /// with values for the arguments)
120 pub ret_ty: TyS,
121 /// The body of the definition (to be evaluated in an environment with
122 /// values for the arguments)
123 pub body: TmS,
124}
125
126impl Def {
127 /// Default constructor for [Def]
128 pub fn new(theory: Theory, args: Row<TyS>, ret_ty: TyS, body: TmS) -> Self {
129 Self {
130 theory,
131 args,
132 ret_ty,
133 body,
134 }
135 }
136}
137
138impl TopDecl {
139 /// Extract the type for a toplevel-declaration of a type.
140 ///
141 /// This should only be used after type checking, when we know that a toplevel
142 /// variable name does in fact point to a toplevel declaration for a type.
143 pub fn as_ty(&self) -> Type {
144 match self {
145 TopDecl::Type(ty) => ty.clone(),
146 _ => panic!("expected type"),
147 }
148 }
149
150 /// Extract the term for a toplevel declaration of a term.
151 ///
152 /// This should only be used after type checking, when we know that a toplevel
153 /// variable name does in fact point to a toplevel declaration for a term.
154 pub fn as_const(&self) -> DefConst {
155 match self {
156 TopDecl::DefConst(d) => d.clone(),
157 _ => panic!("expected const"),
158 }
159 }
160
161 /// Extract the definition for a toplevel term judgment
162 pub fn as_def(&self) -> Def {
163 match self {
164 TopDecl::Def(d) => d.clone(),
165 _ => panic!("expected def"),
166 }
167 }
168}
169
170/// Construct a library of standard theories
171pub fn std_theories() -> HashMap<QualifiedName, Theory> {
172 [
173 (name("ThSchema"), th_schema()),
174 (name("ThCategory"), th_category()),
175 (name("ThSignedCategory"), th_signed_category()),
176 ]
177 .into_iter()
178 .map(|(name, def)| (name.clone(), Theory::new(name.clone(), Rc::new(def))))
179 .collect()
180}
181
182/// Storage for toplevel declarations.
183pub struct Toplevel {
184 /// Library of theories, indexed by name
185 pub theory_library: HashMap<QualifiedName, Theory>,
186 /// The toplevel declarations, indexed by their name.
187 pub declarations: HashMap<TopVarName, TopDecl>,
188}
189
190impl Toplevel {
191 /// Constructor for an empty [Toplevel].
192 pub fn new(theory_library: HashMap<QualifiedName, Theory>) -> Self {
193 Toplevel {
194 theory_library,
195 declarations: HashMap::new(),
196 }
197 }
198
199 /// Lookup a toplevel declaration by name.
200 pub fn lookup(&self, name: TopVarName) -> Option<&TopDecl> {
201 self.declarations.get(&name)
202 }
203}