Skip to main content

lady_deirdre/units/
document.rs

1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Lady Deirdre", a compiler front-end foundation       //
3// technology.                                                                //
4//                                                                            //
5// This work is proprietary software with source-available code.              //
6//                                                                            //
7// To copy, use, distribute, or contribute to this work, you must agree to    //
8// the terms of the General License Agreement:                                //
9//                                                                            //
10// https://github.com/Eliah-Lakhin/lady-deirdre/blob/master/EULA.md           //
11//                                                                            //
12// The agreement grants a Basic Commercial License, allowing you to use       //
13// this work in non-commercial and limited commercial products with a total   //
14// gross revenue cap. To remove this commercial limit for one of your         //
15// products, you must acquire a Full Commercial License.                      //
16//                                                                            //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions.             //
19// Contributions are governed by the "Contributions" section of the General   //
20// License Agreement.                                                         //
21//                                                                            //
22// Copying the work in parts is strictly forbidden, except as permitted       //
23// under the General License Agreement.                                       //
24//                                                                            //
25// If you do not or cannot agree to the terms of this Agreement,              //
26// do not use this work.                                                      //
27//                                                                            //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid.                         //
30//                                                                            //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин).                 //
32// All rights reserved.                                                       //
33////////////////////////////////////////////////////////////////////////////////
34
35use std::{
36    fmt::{Debug, Display, Formatter},
37    iter::FusedIterator,
38};
39
40use crate::{
41    arena::{Entry, Id, Identifiable},
42    lexis::{
43        Length,
44        LineIndex,
45        Site,
46        SiteRef,
47        SourceCode,
48        ToSpan,
49        Token,
50        TokenBuffer,
51        TokenCount,
52        TokenCursor,
53        TokenRef,
54    },
55    syntax::{ErrorRef, Node, NodeRef, SyntaxError, SyntaxTree},
56    units::{CompilationUnit, ImmutableUnit, MutableUnit, VoidWatcher, Watcher},
57};
58
59/// The object that stores the content of an individual file within your
60/// compilation project.
61///
62/// The Document automatically parses the lexical and syntax components of
63/// the programming language grammar and offers methods to inspect this data.
64///
65/// The Document comes in two flavors: mutable and immutable. A mutable document
66/// can accept user-input edits in the source code text, while an immutable
67/// document does not accept edits but is optimized for one-time parsing.
68///
69/// The generic parameter `N` of type [Node] specifies the lexical and syntax
70/// grammar of the language.
71///
72/// Each document instance has a unique [Id] that you can use to distinguish
73/// between two documents or to use as a key in a hash map of documents.
74pub enum Document<N: Node> {
75    /// A document that accepts user-input edits.
76    Mutable(MutableUnit<N>),
77
78    /// A document that does not accept user-input edits but is optimized for
79    /// one-time parsing.
80    Immutable(ImmutableUnit<N>),
81}
82
83impl<N: Node> Debug for Document<N> {
84    #[inline(always)]
85    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
86        match self {
87            Self::Mutable(unit) => Debug::fmt(unit, formatter),
88            Self::Immutable(unit) => Debug::fmt(unit, formatter),
89        }
90    }
91}
92
93impl<N: Node> Display for Document<N> {
94    #[inline(always)]
95    fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
96        match self {
97            Self::Mutable(unit) => Display::fmt(unit, formatter),
98            Self::Immutable(unit) => Display::fmt(unit, formatter),
99        }
100    }
101}
102
103impl<N: Node> Identifiable for Document<N> {
104    #[inline(always)]
105    fn id(&self) -> Id {
106        match self {
107            Self::Mutable(unit) => unit.id(),
108            Self::Immutable(unit) => unit.id(),
109        }
110    }
111}
112
113impl<N: Node> Default for Document<N> {
114    #[inline(always)]
115    fn default() -> Self {
116        Self::Mutable(MutableUnit::default())
117    }
118}
119
120impl<N: Node> From<MutableUnit<N>> for Document<N> {
121    #[inline(always)]
122    fn from(unit: MutableUnit<N>) -> Self {
123        Self::Mutable(unit)
124    }
125}
126
127impl<N: Node> From<ImmutableUnit<N>> for Document<N> {
128    #[inline(always)]
129    fn from(unit: ImmutableUnit<N>) -> Self {
130        Self::Immutable(unit)
131    }
132}
133
134impl<N: Node, S: AsRef<str>> From<S> for Document<N> {
135    #[inline(always)]
136    fn from(string: S) -> Self {
137        Self::Mutable(MutableUnit::from(string))
138    }
139}
140
141impl<N: Node> SourceCode for Document<N> {
142    type Token = N::Token;
143
144    type Cursor<'document> = DocumentCursor<'document, N>;
145
146    type CharIterator<'document> = DocumentCharIter<'document, N>;
147
148    #[inline(always)]
149    fn chars(&self, span: impl ToSpan) -> Self::CharIterator<'_> {
150        match self {
151            Self::Mutable(unit) => DocumentCharIter::Mutable(unit.chars(span)),
152            Self::Immutable(unit) => DocumentCharIter::Immutable(unit.chars(span)),
153        }
154    }
155
156    #[inline(always)]
157    fn has_chunk(&self, entry: &Entry) -> bool {
158        match self {
159            Self::Mutable(unit) => unit.has_chunk(entry),
160            Self::Immutable(unit) => unit.has_chunk(entry),
161        }
162    }
163
164    #[inline(always)]
165    fn get_token(&self, entry: &Entry) -> Option<Self::Token> {
166        match self {
167            Self::Mutable(unit) => unit.get_token(entry),
168            Self::Immutable(unit) => unit.get_token(entry),
169        }
170    }
171
172    #[inline(always)]
173    fn get_site(&self, entry: &Entry) -> Option<Site> {
174        match self {
175            Self::Mutable(unit) => unit.get_site(entry),
176            Self::Immutable(unit) => unit.get_site(entry),
177        }
178    }
179
180    #[inline(always)]
181    fn get_string(&self, entry: &Entry) -> Option<&str> {
182        match self {
183            Self::Mutable(unit) => unit.get_string(entry),
184            Self::Immutable(unit) => unit.get_string(entry),
185        }
186    }
187
188    #[inline(always)]
189    fn get_length(&self, entry: &Entry) -> Option<Length> {
190        match self {
191            Self::Mutable(unit) => unit.get_length(entry),
192            Self::Immutable(unit) => unit.get_length(entry),
193        }
194    }
195
196    #[inline(always)]
197    fn cursor(&self, span: impl ToSpan) -> Self::Cursor<'_> {
198        match self {
199            Self::Mutable(unit) => DocumentCursor::Mutable(unit.cursor(span)),
200            Self::Immutable(unit) => DocumentCursor::Immutable(unit.cursor(span)),
201        }
202    }
203
204    #[inline(always)]
205    fn length(&self) -> Length {
206        match self {
207            Self::Mutable(unit) => unit.length(),
208            Self::Immutable(unit) => unit.length(),
209        }
210    }
211
212    #[inline(always)]
213    fn tokens(&self) -> TokenCount {
214        match self {
215            Self::Mutable(unit) => unit.tokens(),
216            Self::Immutable(unit) => unit.tokens(),
217        }
218    }
219
220    #[inline(always)]
221    fn lines(&self) -> &LineIndex {
222        match self {
223            Self::Mutable(unit) => unit.lines(),
224            Self::Immutable(unit) => unit.lines(),
225        }
226    }
227}
228
229impl<N: Node> SyntaxTree for Document<N> {
230    type Node = N;
231
232    type NodeIterator<'document> = DocumentNodeIter<'document, N>;
233
234    type ErrorIterator<'document> = DocumentErrorIter<'document, N>;
235
236    #[inline(always)]
237    fn root_node_ref(&self) -> NodeRef {
238        match self {
239            Self::Mutable(unit) => unit.root_node_ref(),
240            Self::Immutable(unit) => unit.root_node_ref(),
241        }
242    }
243
244    #[inline(always)]
245    fn node_refs(&self) -> Self::NodeIterator<'_> {
246        match self {
247            Self::Mutable(unit) => DocumentNodeIter::Mutable(unit.node_refs()),
248            Self::Immutable(unit) => DocumentNodeIter::Immutable(unit.node_refs()),
249        }
250    }
251
252    #[inline(always)]
253    fn error_refs(&self) -> Self::ErrorIterator<'_> {
254        match self {
255            Self::Mutable(unit) => DocumentErrorIter::Mutable(unit.error_refs()),
256            Self::Immutable(unit) => DocumentErrorIter::Immutable(unit.error_refs()),
257        }
258    }
259
260    #[inline(always)]
261    fn has_node(&self, entry: &Entry) -> bool {
262        match self {
263            Self::Mutable(unit) => unit.has_node(entry),
264            Self::Immutable(unit) => unit.has_node(entry),
265        }
266    }
267
268    #[inline(always)]
269    fn get_node(&self, entry: &Entry) -> Option<&Self::Node> {
270        match self {
271            Self::Mutable(unit) => unit.get_node(entry),
272            Self::Immutable(unit) => unit.get_node(entry),
273        }
274    }
275
276    #[inline(always)]
277    fn get_node_mut(&mut self, entry: &Entry) -> Option<&mut Self::Node> {
278        match self {
279            Self::Mutable(unit) => unit.get_node_mut(entry),
280            Self::Immutable(unit) => unit.get_node_mut(entry),
281        }
282    }
283
284    #[inline(always)]
285    fn has_error(&self, entry: &Entry) -> bool {
286        match self {
287            Self::Mutable(unit) => unit.has_error(entry),
288            Self::Immutable(unit) => unit.has_error(entry),
289        }
290    }
291
292    #[inline(always)]
293    fn get_error(&self, entry: &Entry) -> Option<&SyntaxError> {
294        match self {
295            Self::Mutable(unit) => unit.get_error(entry),
296            Self::Immutable(unit) => unit.get_error(entry),
297        }
298    }
299}
300
301impl<N: Node> CompilationUnit for Document<N> {
302    #[inline(always)]
303    fn is_mutable(&self) -> bool {
304        match self {
305            Self::Mutable(..) => true,
306            Self::Immutable(..) => false,
307        }
308    }
309
310    #[inline(always)]
311    fn into_token_buffer(self) -> TokenBuffer<N::Token> {
312        match self {
313            Self::Mutable(unit) => unit.into_token_buffer(),
314            Self::Immutable(unit) => unit.into_token_buffer(),
315        }
316    }
317
318    #[inline(always)]
319    fn into_document(self) -> Document<N> {
320        self
321    }
322
323    #[inline(always)]
324    fn into_mutable_unit(self) -> MutableUnit<N> {
325        match self {
326            Self::Mutable(unit) => unit,
327            Self::Immutable(unit) => unit.into_mutable_unit(),
328        }
329    }
330
331    #[inline(always)]
332    fn into_immutable_unit(self) -> ImmutableUnit<N> {
333        match self {
334            Self::Mutable(unit) => unit.into_immutable_unit(),
335            Self::Immutable(unit) => unit,
336        }
337    }
338
339    #[inline(always)]
340    fn cover(&self, span: impl ToSpan) -> NodeRef {
341        match self {
342            Self::Mutable(unit) => unit.cover(span),
343            Self::Immutable(unit) => unit.cover(span),
344        }
345    }
346}
347
348impl<N: Node> Document<N> {
349    /// Creates a mutable version of the Document.
350    ///
351    /// This type of document accepts user-input edits.
352    ///
353    /// The parameter could be a [TokenBuffer] or just an arbitrary string.
354    #[inline(always)]
355    pub fn new_mutable(text: impl Into<TokenBuffer<N::Token>>) -> Self {
356        Self::Mutable(MutableUnit::new(text))
357    }
358
359    /// Creates an immutable version of the Document.
360    ///
361    /// This type of document does not accept user-input edits but
362    /// optimized for one-time parsing.
363    ///
364    /// The parameter could be a [TokenBuffer] or just an arbitrary string.
365    #[inline(always)]
366    pub fn new_immutable(text: impl Into<TokenBuffer<N::Token>>) -> Self {
367        Self::Immutable(ImmutableUnit::new(text))
368    }
369
370    /// Writes user-input edit into this document.
371    ///
372    /// The Document instantly reparses a part of the underlying source code
373    /// relative to the edit.
374    ///
375    /// The reparsing process usually takes a short time if the edit is short,
376    /// and even if the entire source code is big. Therefore, it is acceptable
377    /// to call this function on every user-input action. For instance, you can
378    /// call this function on every content change event from the text editor.
379    ///
380    /// The first parameter `span` specifies a span of the current source code
381    /// text that you want to rewrite (empty spans denote insertion).
382    ///
383    /// The `span` is usually a range in units of various measurement types.
384    ///
385    /// For example, `10..20` is a span of nine Unicode chars starting
386    /// from the tenth char. Line-column index or token sites are also
387    /// acceptable bounds. See [ToSpan] for details.
388    ///
389    /// **Panic**
390    ///
391    /// Panics if the Document is not mutable, or if the specified span is not
392    /// valid for this document.
393    #[inline(always)]
394    pub fn write(&mut self, span: impl ToSpan, text: impl AsRef<str>) {
395        self.write_and_watch(span, text, &mut VoidWatcher)
396    }
397
398    /// Writes user-input edit into this document, and collects all syntax tree
399    /// components that have been affected by this edit.
400    ///
401    /// This function is similar to the [Document::write] but has
402    /// an additional `watcher` parameter of type [Watcher] into which the
403    /// document reports all syntax changes occurred during the incremental
404    /// reparsing.
405    ///
406    /// **Panic**
407    ///
408    /// Panics if the Document is not mutable, or if the specified span is not
409    /// valid for this document.
410    #[inline(always)]
411    pub fn write_and_watch(
412        &mut self,
413        span: impl ToSpan,
414        text: impl AsRef<str>,
415        watcher: &mut impl Watcher,
416    ) {
417        let unit = match self.as_mutable() {
418            Some(unit) => unit,
419            None => panic!("Specified Document is not mutable."),
420        };
421
422        unit.write_and_watch(span, text, watcher);
423    }
424
425    /// A convenient function that returns a reference to the document's
426    /// inner [MutableUnit] if the document is mutable. Otherwise returns None.
427    #[inline(always)]
428    pub fn as_mutable(&mut self) -> Option<&mut MutableUnit<N>> {
429        match self {
430            Self::Mutable(unit) => Some(unit),
431            Self::Immutable(..) => None,
432        }
433    }
434
435    /// If the document immutable, creates and returns a new instance of
436    /// the mutable document with the same source code.
437    ///
438    /// Otherwise, if the document is already mutable, returns this instance.
439    ///
440    /// This function is more efficient than creating the mutable document
441    /// from scratch by manually copying the inner text, because the underlying
442    /// algorithm could transfer already parsed lexical structure and the text
443    /// content as they are.
444    #[inline(always)]
445    pub fn into_mutable(self) -> Self {
446        match self {
447            Self::Mutable(..) => self,
448            Self::Immutable(unit) => Self::Mutable(unit.into_mutable_unit()),
449        }
450    }
451
452    /// If the document mutable, creates and returns a new instance of
453    /// the immutable document with the same source code.
454    ///
455    /// Otherwise, if the document is already immutable, returns this instance.
456    ///
457    /// This function is more efficient than creating the immutable document
458    /// from scratch by manually copying the inner text, because the underlying
459    /// algorithm could transfer already parsed lexical structure and the text
460    /// content as they are.
461    #[inline(always)]
462    pub fn into_immutable(self) -> Self {
463        match self {
464            Self::Mutable(unit) => Self::Immutable(unit.into_immutable_unit()),
465            Self::Immutable(..) => self,
466        }
467    }
468}
469
470impl<T: Token> TokenBuffer<T> {
471    /// Turns this token buffer into **mutable** Document.
472    ///
473    /// The `N` generic parameter specifies a type of the syntax tree [Node]
474    /// with the `T` [lexis](Node::Token).
475    #[inline(always)]
476    pub fn into_document<N>(self) -> Document<N>
477    where
478        N: Node<Token = T>,
479    {
480        self.into_mutable_unit().into()
481    }
482}
483
484pub enum DocumentCursor<'document, N: Node> {
485    Mutable(<MutableUnit<N> as SourceCode>::Cursor<'document>),
486    Immutable(<ImmutableUnit<N> as SourceCode>::Cursor<'document>),
487}
488
489impl<'document, N: Node> Identifiable for DocumentCursor<'document, N> {
490    #[inline(always)]
491    fn id(&self) -> Id {
492        match self {
493            Self::Mutable(cursor) => cursor.id(),
494            Self::Immutable(cursor) => cursor.id(),
495        }
496    }
497}
498
499impl<'document, N: Node> TokenCursor<'document> for DocumentCursor<'document, N> {
500    type Token = N::Token;
501
502    #[inline(always)]
503    fn advance(&mut self) -> bool {
504        match self {
505            Self::Mutable(cursor) => cursor.advance(),
506            Self::Immutable(cursor) => cursor.advance(),
507        }
508    }
509
510    #[inline(always)]
511    fn skip(&mut self, distance: TokenCount) {
512        match self {
513            Self::Mutable(cursor) => cursor.skip(distance),
514            Self::Immutable(cursor) => cursor.skip(distance),
515        }
516    }
517
518    #[inline(always)]
519    fn token(&mut self, distance: TokenCount) -> Self::Token {
520        match self {
521            Self::Mutable(cursor) => cursor.token(distance),
522            Self::Immutable(cursor) => cursor.token(distance),
523        }
524    }
525
526    #[inline(always)]
527    fn site(&mut self, distance: TokenCount) -> Option<Site> {
528        match self {
529            Self::Mutable(cursor) => cursor.site(distance),
530            Self::Immutable(cursor) => cursor.site(distance),
531        }
532    }
533
534    #[inline(always)]
535    fn length(&mut self, distance: TokenCount) -> Option<Length> {
536        match self {
537            Self::Mutable(cursor) => cursor.length(distance),
538            Self::Immutable(cursor) => cursor.length(distance),
539        }
540    }
541
542    #[inline(always)]
543    fn string(&mut self, distance: TokenCount) -> Option<&'document str> {
544        match self {
545            Self::Mutable(cursor) => cursor.string(distance),
546            Self::Immutable(cursor) => cursor.string(distance),
547        }
548    }
549
550    #[inline(always)]
551    fn token_ref(&mut self, distance: TokenCount) -> TokenRef {
552        match self {
553            Self::Mutable(cursor) => cursor.token_ref(distance),
554            Self::Immutable(cursor) => cursor.token_ref(distance),
555        }
556    }
557
558    #[inline(always)]
559    fn site_ref(&mut self, distance: TokenCount) -> SiteRef {
560        match self {
561            Self::Mutable(cursor) => cursor.site_ref(distance),
562            Self::Immutable(cursor) => cursor.site_ref(distance),
563        }
564    }
565
566    #[inline(always)]
567    fn end_site_ref(&mut self) -> SiteRef {
568        match self {
569            Self::Mutable(cursor) => cursor.end_site_ref(),
570            Self::Immutable(cursor) => cursor.end_site_ref(),
571        }
572    }
573}
574
575pub enum DocumentCharIter<'document, N: Node> {
576    Mutable(<MutableUnit<N> as SourceCode>::CharIterator<'document>),
577    Immutable(<ImmutableUnit<N> as SourceCode>::CharIterator<'document>),
578}
579
580impl<'document, N: Node> Iterator for DocumentCharIter<'document, N> {
581    type Item = char;
582
583    #[inline(always)]
584    fn next(&mut self) -> Option<Self::Item> {
585        match self {
586            Self::Mutable(iterator) => iterator.next(),
587            Self::Immutable(iterator) => iterator.next(),
588        }
589    }
590}
591
592impl<'document, N: Node> FusedIterator for DocumentCharIter<'document, N> {}
593
594pub enum DocumentNodeIter<'document, N: Node> {
595    Mutable(<MutableUnit<N> as SyntaxTree>::NodeIterator<'document>),
596    Immutable(<ImmutableUnit<N> as SyntaxTree>::NodeIterator<'document>),
597}
598
599impl<'document, N: Node> Iterator for DocumentNodeIter<'document, N> {
600    type Item = NodeRef;
601
602    #[inline(always)]
603    fn next(&mut self) -> Option<Self::Item> {
604        match self {
605            Self::Mutable(iterator) => iterator.next(),
606            Self::Immutable(iterator) => iterator.next(),
607        }
608    }
609}
610
611impl<'document, N: Node> FusedIterator for DocumentNodeIter<'document, N> {}
612
613pub enum DocumentErrorIter<'document, N: Node> {
614    Mutable(<MutableUnit<N> as SyntaxTree>::ErrorIterator<'document>),
615    Immutable(<ImmutableUnit<N> as SyntaxTree>::ErrorIterator<'document>),
616}
617
618impl<'document, N: Node> Iterator for DocumentErrorIter<'document, N> {
619    type Item = ErrorRef;
620
621    #[inline(always)]
622    fn next(&mut self) -> Option<Self::Item> {
623        match self {
624            Self::Mutable(iterator) => iterator.next(),
625            Self::Immutable(iterator) => iterator.next(),
626        }
627    }
628}
629
630impl<'document, N: Node> FusedIterator for DocumentErrorIter<'document, N> {}