Skip to main content

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}