cl_typeck/entry.rs
1//! An [Entry] is an accessor for [nodes](Handle) in a [Table].
2//!
3//! There are two kinds of entry:
4//! - [Entry]: Provides getters for an entry's fields, and an implementation of
5//! [Display](std::fmt::Display)
6//! - [EntryMut]: Provides setters for an entry's fields, and an [`as_ref`](EntryMut::as_ref) method
7//! to demote to an [Entry].
8
9use crate::table::SymMap;
10
11use cl_ast::{
12 Expr,
13 types::{Path, Symbol as Sym},
14};
15
16use crate::{
17 handle::Handle,
18 stage::categorize as cat,
19 table::{NodeKind, Table},
20 type_expression::{self as tex, TypeExpression},
21 type_kind::TypeKind,
22};
23
24mod debug;
25mod display;
26
27impl Handle {
28 /// Constructs an [Entry] from this handle and a [Table] ref
29 pub const fn to_entry<'t>(self, table: &'t Table) -> Entry<'t> {
30 Entry { id: self, table }
31 }
32
33 /// Constructs an [EntryMut] from this handle and a [Table] ref mut
34 pub const fn to_entry_mut<'t>(self, table: &'t mut Table) -> EntryMut<'t> {
35 EntryMut { id: self, table }
36 }
37}
38
39/// An immutable, object-like entry in a [`Table`].
40///
41/// [`Entry`] wraps a [`Table`] and a [`Handle`], and provides an ergonomic interface
42/// for querying information about the state of the node at that [`Handle`].
43///
44/// Its mutable counterpart, [`EntryMut`], provides a similar interface for *modifying*
45/// the state of the [`Table`].
46pub struct Entry<'t> {
47 table: &'t Table,
48 id: Handle,
49}
50
51macro_rules! impl_entry_ {
52 () => {
53 /// Gets the [Handle] associated with this Entry
54 pub const fn id(&self) -> Handle {
55 self.id
56 }
57
58 /// Gets the [Table] associated with this Entry
59 pub const fn inner(&'t self) -> &'t Table {
60 self.table
61 }
62
63 /// Gets the [NodeKind] of this [Entry] in the [Table]
64 pub fn kind(&self) -> Option<&NodeKind> {
65 self.table.kind(self.id)
66 }
67
68 /// Gets the [Entry] of the root node in the [Table]
69 pub const fn root(&self) -> Entry<'_> {
70 Entry { id: self.table.root(), table: self.table }
71 }
72
73 /// Gets the children of this node
74 pub fn children(&self) -> Option<&SymMap<Handle>> {
75 self.table.children(self.id)
76 }
77
78 /// Gets the lazy-imports list for this node
79 pub fn lazy_imports(&self) -> Option<&SymMap<Path>> {
80 self.table.lazy_imports(self.id)
81 }
82
83 /// Gets the glob-imports list for this node
84 pub fn glob_imports(&self) -> Option<&[Path]> {
85 self.table.glob_imports(self.id)
86 }
87
88 /// Gets the meta-[Expr] list for this node
89 pub fn meta(&self) -> Option<&[Expr]> {
90 self.table.meta(self.id)
91 }
92
93 /// Gets an identifying [Sym]bol for this node, if possible
94 pub fn name(&self) -> Option<Sym> {
95 self.table.name(self.id)
96 }
97 };
98}
99
100impl<'t> Entry<'t> {
101 /// Constructs a new [`Entry`] from shared [`&Table`](Table) and a [`Handle`].
102 pub const fn new(table: &'t Table, id: Handle) -> Self {
103 Self { table, id }
104 }
105
106 impl_entry_!();
107
108 /// Constructs another [Entry] with the given [Handle]
109 pub const fn with_id(&self, id: Handle) -> Entry<'t> {
110 Self { table: self.table, id }
111 }
112
113 /// [Navigates](Table::nav) to another [Entry]
114 pub fn nav(&self, path: &[Sym]) -> Option<Entry<'t>> {
115 Some(Entry { id: self.table.nav(self.id, path)?, table: self.table })
116 }
117
118 /// Gets the [parent](Table::parent) of this [Entry]
119 pub fn parent(&self) -> Option<Entry<'t>> {
120 Some(Entry { id: *self.table.parent(self.id)?, ..*self })
121 }
122
123 /// Gets the [TypeKind] of this [Entry]
124 pub fn ty(&self) -> Option<&'t TypeKind> {
125 self.table.ty(self.id)
126 }
127
128 /// Gets the [`impl` target](Table::impl_target) of this [Entry]
129 pub fn impl_target(&self) -> Option<Entry<'_>> {
130 Some(Entry { id: self.table.impl_target(self.id)?, ..*self })
131 }
132
133 /// Gets the [`Self` type](Table::selfty) of this [Entry]
134 pub fn selfty(&self) -> Option<Entry<'_>> {
135 Some(Entry { id: self.table.selfty(self.id)?, ..*self })
136 }
137}
138
139/// A mutable, object-like entry in a [`Table`].
140///
141/// [`Entry`] wraps a [`Table`] and a [`Handle`], and provides an ergonomic interface
142/// for querying information about the state of the node at that [`Handle`].
143///
144/// Its immutable counterpart, [`Entry`], provides a similar interface for *querying*
145/// the state of the [`Table`], which may be shared among multiple [`Entries`](Entry).
146#[derive(Debug)]
147pub struct EntryMut<'t> {
148 table: &'t mut Table,
149 id: Handle,
150}
151
152impl<'t> EntryMut<'t> {
153 /// Constructs a new [`EntryMut`] from a [`&mut Table`](Table) and a [`Handle`].
154 pub fn new(table: &'t mut Table, id: Handle) -> Self {
155 Self { table, id }
156 }
157
158 impl_entry_!();
159
160 /// Gets the [`TypeKind`] of this [`EntryMut`]
161 pub fn ty(&self) -> Option<&TypeKind> {
162 self.table.ty(self.id)
163 }
164
165 /// Reborrows the inner [`Table`] reference
166 pub fn inner_mut(&mut self) -> &mut Table {
167 self.table
168 }
169
170 /// Cheaply constructs an [`Entry`] from this [`EntryMut`]
171 pub fn as_ref(&self) -> Entry<'_> {
172 Entry { table: self.table, id: self.id }
173 }
174
175 /// Evaluates a [TypeExpression] in this entry's context
176 pub fn evaluate<Out>(&mut self, ty: &impl TypeExpression<Out>) -> Result<Out, tex::Error> {
177 let Self { table, id } = self;
178 ty.evaluate(table, *id)
179 }
180
181 /// Calls [categorize](cat::categorize) on this node in the table
182 pub fn categorize(&mut self) -> Result<(), cat::Error> {
183 cat::categorize(self.table, self.id)
184 }
185
186 /// Constructs a new Handle with the provided parent [Handle]
187 pub fn with_id(&mut self, parent: Handle) -> EntryMut<'_> {
188 EntryMut { table: self.table, id: parent }
189 }
190
191 /// [Navigates](Table::nav) to another [`EntryMut`], reborrowing the table.
192 pub fn nav(&mut self, path: &[Sym]) -> Option<EntryMut<'_>> {
193 Some(EntryMut { id: self.table.nav(self.id, path)?, table: self.table })
194 }
195
196 /// Constructs a new node with the given [NodeKind], and returns its [EntryMut].
197 pub fn new_entry(&mut self, kind: NodeKind) -> EntryMut<'_> {
198 let id = self.table.new_entry(self.id, kind);
199 self.with_id(id)
200 }
201
202 /// Adds an existing node as a `child` with the given `name`.
203 ///
204 /// If that name is already taken, its previous [Handle] is returned.
205 pub fn add_child(&mut self, name: Sym, child: Handle) -> Option<Handle> {
206 self.table.add_child(self.id, name, child)
207 }
208
209 /// Adds a [lazy-import](Table::lazy_imports) edge from [`name`](Sym) to [`path`](Path)
210 pub fn add_import(&mut self, name: Sym, path: Path) {
211 self.table.add_import(self.id, name, path);
212 }
213
214 /// Adds a [glob-import](Table::glob_imports) edge to [`path`](Path).
215 ///
216 /// Glob imports act as secondary (tertiary, etc.) parent edges,
217 /// which are always transparent. They are checked in reverse order,
218 /// giving later glob imports precedence over earlier ones.
219 pub fn add_glob(&mut self, path: Path) {
220 self.table.add_glob(self.id, path);
221 }
222
223 /// Sets the [`name`](Table::name) of this [`EntryMut`].
224 pub fn set_name(&mut self, name: Sym) -> Option<Sym> {
225 self.table.set_name(self.id, name)
226 }
227
228 /// Sets the [`TypeKind`] of this [`EntryMut`]
229 pub fn set_ty(&mut self, kind: TypeKind) -> Option<TypeKind> {
230 self.table.set_ty(self.id, kind)
231 }
232
233 /// Appends a list of [Expr]s to this [`EntryMut`]'s [meta](Table::meta).
234 pub fn set_meta(&mut self, meta: Vec<Expr>) {
235 self.table.set_meta(self.id, meta)
236 }
237
238 /// Adds a single [Expr] to this [`EntryMut`]'s [meta](Table::meta)
239 pub fn add_meta(&mut self, meta: Expr) {
240 self.table.add_meta(self.id, meta)
241 }
242
243 /// Sets the [`impl` target](Table::impl_target) to [`target`](Handle)
244 pub fn set_impl_target(&mut self, target: Handle) -> Option<Handle> {
245 self.table.set_impl_target(self.id, target)
246 }
247
248 /// Marks this [EntryMut] as unchecked.
249 pub fn mark_unchecked(&mut self) {
250 self.table.mark_unchecked(self.id)
251 }
252
253 /// Marks this [EntryMut] as an `impl` item
254 pub fn mark_impl_item(&mut self) {
255 self.table.mark_impl_item(self.id)
256 }
257
258 /// Marks this [EntryMut] as a [`lang item`](Table::get_lang_item)
259 pub fn mark_lang_item(&mut self, lang_item: &'static str) {
260 self.table.mark_lang_item(lang_item, self.id)
261 }
262}