Skip to main content

m2_syn/lex/
token_stream.rs

1use std::fmt::{Display, Formatter, Result};
2use std::sync::Arc;
3use std::vec::IntoIter;
4
5use crate::{Source, Span, Spanned, lexer::punctuation_would_merge};
6
7#[path = "token_stream/delim.rs"]
8pub mod delim;
9use delim::{Delimiter, DelimiterKind};
10
11#[path = "token_stream/punct.rs"]
12mod punct;
13pub use punct::Punct;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16/// The lexical category of a literal token.
17pub enum LiteralKind {
18    /// A double-quoted string.
19    String,
20    /// A slash-delimited raw string.
21    RawString,
22    /// An integer number.
23    Integer,
24    /// A floating-point number.
25    Float,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29/// A literal spelling together with its lexical category and source span.
30pub struct LiteralToken {
31    /// The literal's lexical category.
32    pub kind: LiteralKind,
33    span: Span,
34    leading_trivia: LeadingTrivia,
35    trailing_trivia: TrailingTrivia,
36}
37
38impl LiteralToken {
39    /// Creates a literal token from its source span.
40    pub fn from_span(kind: LiteralKind, span: Span) -> Self {
41        Self {
42            kind,
43            span,
44            leading_trivia: LeadingTrivia::default(),
45            trailing_trivia: TrailingTrivia::default(),
46        }
47    }
48
49    /// Creates a literal token.
50    pub fn new(kind: LiteralKind, text: impl Into<Arc<str>>, span: Span) -> Self {
51        Self {
52            kind,
53            span: span_for_spelling(text.into(), span),
54            leading_trivia: LeadingTrivia::default(),
55            trailing_trivia: TrailingTrivia::default(),
56        }
57    }
58
59    /// Returns the complete source spelling, including string delimiters.
60    ///
61    /// # Panics
62    ///
63    /// Panics when `sources` cannot resolve this token's span.
64    pub fn text(&self) -> &str {
65        self.span
66            .text()
67            .expect("literal spans must resolve to source text")
68    }
69}
70
71impl Spanned for LiteralToken {
72    fn try_span(&self) -> Option<Span> {
73        Some(self.span.clone())
74    }
75}
76
77impl Lex for LiteralToken {
78    fn to_tokens(&self, output: &mut TokenStream) {
79        output.push(TokenTree::Literal(self.clone()));
80    }
81}
82
83impl Terminal for LiteralToken {
84    fn leading_trivia(&self) -> &LeadingTrivia {
85        &self.leading_trivia
86    }
87
88    fn leading_trivia_mut(&mut self) -> &mut LeadingTrivia {
89        &mut self.leading_trivia
90    }
91
92    fn trailing_trivia(&self) -> &TrailingTrivia {
93        &self.trailing_trivia
94    }
95
96    fn trailing_trivia_mut(&mut self) -> &mut TrailingTrivia {
97        &mut self.trailing_trivia
98    }
99}
100
101#[derive(Debug, Clone, PartialEq, Eq)]
102/// An identifier spelling and its source span.
103pub struct IdentToken {
104    span: Span,
105    source_qualifier: Option<Span>,
106    index_qualifier: Option<Span>,
107    leading_trivia: LeadingTrivia,
108    trailing_trivia: TrailingTrivia,
109}
110
111impl IdentToken {
112    /// Creates an identifier from its source span.
113    ///
114    /// # Panics
115    ///
116    /// Panics when the span cannot resolve its source text.
117    pub fn from_span(span: Span) -> Self {
118        let text = span
119            .text()
120            .expect("identifier spans must resolve to source text");
121        let (source_qualifier, index_qualifier) = identifier_qualifier_spans(text, &span);
122        Self {
123            span,
124            source_qualifier,
125            index_qualifier,
126            leading_trivia: LeadingTrivia::default(),
127            trailing_trivia: TrailingTrivia::default(),
128        }
129    }
130
131    /// Creates an identifier token.
132    pub fn new(text: impl Into<Arc<str>>, span: Span) -> Self {
133        Self::from_span(span_for_spelling(text.into(), span))
134    }
135
136    /// Returns the identifier spelling.
137    ///
138    /// # Panics
139    ///
140    /// Panics when `sources` cannot resolve this token's span.
141    pub fn text(&self) -> &str {
142        self.span
143            .text()
144            .expect("identifier spans must resolve to source text")
145    }
146
147    /// Returns the `Source$` prefix, including its `$`, when present.
148    pub fn source_qualifier(&self) -> Option<&Span> {
149        self.source_qualifier.as_ref()
150    }
151
152    /// Returns the `$0` suffix, including its `$`, when present.
153    pub fn index_qualifier(&self) -> Option<&Span> {
154        self.index_qualifier.as_ref()
155    }
156}
157
158impl Spanned for IdentToken {
159    fn try_span(&self) -> Option<Span> {
160        Some(self.span.clone())
161    }
162}
163
164impl Lex for IdentToken {
165    fn to_tokens(&self, output: &mut TokenStream) {
166        output.push(TokenTree::Ident(self.clone()));
167    }
168}
169
170impl Terminal for IdentToken {
171    fn leading_trivia(&self) -> &LeadingTrivia {
172        &self.leading_trivia
173    }
174
175    fn leading_trivia_mut(&mut self) -> &mut LeadingTrivia {
176        &mut self.leading_trivia
177    }
178
179    fn trailing_trivia(&self) -> &TrailingTrivia {
180        &self.trailing_trivia
181    }
182
183    fn trailing_trivia_mut(&mut self) -> &mut TrailingTrivia {
184        &mut self.trailing_trivia
185    }
186}
187
188#[derive(Debug, Clone, PartialEq, Eq)]
189/// A delimited raw token stream.
190pub struct TokenGroup {
191    delimiter: Delimiter,
192    stream: TokenStream,
193    leading_trivia: LeadingTrivia,
194    trailing_trivia: TrailingTrivia,
195}
196
197impl Spanned for TokenGroup {
198    fn try_span(&self) -> Option<Span> {
199        self.delimiter.try_span()
200    }
201}
202
203impl TokenGroup {
204    /// Creates a group from its delimiter and contents.
205    pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self {
206        Self {
207            delimiter,
208            stream,
209            leading_trivia: LeadingTrivia::default(),
210            trailing_trivia: TrailingTrivia::default(),
211        }
212    }
213
214    /// Borrows the group's delimiter data.
215    pub fn delimiter(&self) -> &Delimiter {
216        &self.delimiter
217    }
218
219    /// Returns the group's delimiter family.
220    pub fn delim_kind(&self) -> DelimiterKind {
221        self.delimiter.kind
222    }
223
224    /// Borrows the tokens inside the group.
225    pub fn stream(&self) -> &TokenStream {
226        &self.stream
227    }
228
229    /// Mutably borrows the tokens inside the group.
230    pub fn stream_mut(&mut self) -> &mut TokenStream {
231        &mut self.stream
232    }
233
234    /// Consumes the group and returns its contents.
235    pub fn into_stream(self) -> TokenStream {
236        self.stream
237    }
238}
239
240impl Lex for TokenGroup {
241    fn to_tokens(&self, output: &mut TokenStream) {
242        output.push(TokenTree::Group(self.clone()));
243    }
244}
245
246impl Terminal for TokenGroup {
247    fn leading_trivia(&self) -> &LeadingTrivia {
248        &self.leading_trivia
249    }
250
251    fn leading_trivia_mut(&mut self) -> &mut LeadingTrivia {
252        &mut self.leading_trivia
253    }
254
255    fn trailing_trivia(&self) -> &TrailingTrivia {
256        &self.trailing_trivia
257    }
258
259    fn trailing_trivia_mut(&mut self) -> &mut TrailingTrivia {
260        &mut self.trailing_trivia
261    }
262}
263
264#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
265/// The lexical category of source trivia.
266pub enum TriviaKind {
267    /// A comment extending to the end of a line.
268    LineComment,
269    /// A delimited block comment.
270    BlockComment,
271}
272
273#[derive(Debug, Clone, PartialEq, Eq, Hash, Spanned)]
274/// A comment retained alongside a lexical atom.
275pub struct Trivia {
276    kind: TriviaKind,
277    span: Span,
278}
279
280impl Trivia {
281    /// Creates trivia from its category and source span.
282    pub fn from_span(kind: TriviaKind, span: Span) -> Self {
283        Self { kind, span }
284    }
285
286    /// Creates trivia from its category, exact text, and span.
287    pub fn new(kind: TriviaKind, text: impl Into<Arc<str>>, span: Span) -> Self {
288        Self {
289            kind,
290            span: span_for_spelling(text.into(), span),
291        }
292    }
293
294    /// Returns the trivia category.
295    pub fn kind(&self) -> TriviaKind {
296        self.kind
297    }
298
299    /// Returns the trivia exactly as it appeared in source.
300    ///
301    /// # Panics
302    ///
303    /// Panics when `sources` cannot resolve this trivia's span.
304    pub fn text(&self) -> &str {
305        self.span
306            .text()
307            .expect("trivia spans must resolve to source text")
308    }
309}
310
311impl Lex for Trivia {
312    fn to_tokens(&self, output: &mut TokenStream) {
313        output.push_trailing_trivia(self.clone());
314    }
315}
316
317#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
318/// Comments owned by the typed terminal to their left.
319pub struct TrailingTrivia(Vec<Trivia>);
320
321impl TrailingTrivia {
322    /// Creates retained trailing trivia from raw trivia tokens.
323    pub fn new(trivia: impl IntoIterator<Item = Trivia>) -> Self {
324        Self(trivia.into_iter().collect())
325    }
326
327    /// Borrows the retained trivia in source order.
328    pub fn as_slice(&self) -> &[Trivia] {
329        &self.0
330    }
331
332    /// Mutably borrows the retained trivia in source order.
333    pub fn as_mut_vec(&mut self) -> &mut Vec<Trivia> {
334        &mut self.0
335    }
336
337    /// Reports whether no comments follow the terminal.
338    pub fn is_empty(&self) -> bool {
339        self.0.is_empty()
340    }
341
342    /// Consumes the collection and returns its trivia tokens.
343    pub fn into_vec(self) -> Vec<Trivia> {
344        self.0
345    }
346}
347
348impl FromIterator<Trivia> for TrailingTrivia {
349    fn from_iter<T: IntoIterator<Item = Trivia>>(iter: T) -> Self {
350        Self::new(iter)
351    }
352}
353
354impl Spanned for TrailingTrivia {
355    fn try_span(&self) -> Option<Span> {
356        Span::join_all(self.0.iter().map(Spanned::try_span))
357    }
358}
359
360impl Lex for TrailingTrivia {
361    fn to_tokens(&self, output: &mut TokenStream) {
362        self.0.to_tokens(output);
363    }
364}
365
366#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
367/// Comments owned by the typed terminal to their right.
368pub struct LeadingTrivia(Vec<Trivia>);
369
370impl LeadingTrivia {
371    /// Creates leading trivia from raw trivia tokens.
372    pub fn new(trivia: impl IntoIterator<Item = Trivia>) -> Self {
373        Self(trivia.into_iter().collect())
374    }
375
376    /// Borrows the retained trivia in source order.
377    pub fn as_slice(&self) -> &[Trivia] {
378        &self.0
379    }
380
381    /// Mutably borrows the comment storage in source order.
382    pub fn as_mut_vec(&mut self) -> &mut Vec<Trivia> {
383        &mut self.0
384    }
385
386    /// Reports whether the block is empty.
387    pub fn is_empty(&self) -> bool {
388        self.0.is_empty()
389    }
390
391    /// Consumes the collection and returns its comments.
392    pub fn into_vec(self) -> Vec<Trivia> {
393        self.0
394    }
395}
396
397impl FromIterator<Trivia> for LeadingTrivia {
398    fn from_iter<T: IntoIterator<Item = Trivia>>(iter: T) -> Self {
399        Self::new(iter)
400    }
401}
402
403impl Spanned for LeadingTrivia {
404    fn try_span(&self) -> Option<Span> {
405        Span::join_all(self.0.iter().map(Spanned::try_span))
406    }
407}
408
409impl Lex for LeadingTrivia {
410    fn to_tokens(&self, output: &mut TokenStream) {
411        for trivia in self.0.iter().cloned() {
412            output.push_leading_trivia(trivia);
413        }
414    }
415}
416
417#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Spanned)]
418/// Comment blocks owned by one structural syntax item.
419///
420/// Outer comments are complete-line `--` blocks documenting the item on
421/// their right. Inner comments occur within the item, including delimited
422/// block comments and `--` comments following code on the same line.
423pub struct CommentTrivia {
424    outer: Vec<Trivia>,
425    inner: Vec<Trivia>,
426}
427
428impl CommentTrivia {
429    /// Borrows the complete-line comment blocks attached from above.
430    pub fn outer(&self) -> &[Trivia] {
431        &self.outer
432    }
433
434    /// Borrows comments contained by the owning syntax item.
435    pub fn inner(&self) -> &[Trivia] {
436        &self.inner
437    }
438
439    /// Reports whether the owner has no retained comments.
440    pub fn is_empty(&self) -> bool {
441        self.outer.is_empty() && self.inner.is_empty()
442    }
443
444    pub(crate) fn take_from_cell(tokens: &mut TokenStream) -> Self {
445        let mut outer = Vec::new();
446        if let Some(first) = tokens.0.first_mut() {
447            let leading = first.leading_trivia_mut().as_mut_vec();
448            let mut retained = Vec::with_capacity(leading.len());
449            for trivia in std::mem::take(leading) {
450                if trivia.kind() == TriviaKind::LineComment {
451                    outer.push(trivia);
452                } else {
453                    retained.push(trivia);
454                }
455            }
456            *leading = retained;
457        }
458        let mut inner = take_stream_comments(tokens);
459        sort_comments(&mut outer);
460        sort_comments(&mut inner);
461        Self { outer, inner }
462    }
463
464    pub(crate) fn take_inner(tokens: &mut TokenStream) -> Self {
465        let mut inner = take_stream_comments(tokens);
466        sort_comments(&mut inner);
467        Self {
468            outer: Vec::new(),
469            inner,
470        }
471    }
472
473    pub(crate) fn append(&mut self, mut comments: Self) {
474        self.outer.append(&mut comments.outer);
475        self.inner.append(&mut comments.inner);
476        sort_comments(&mut self.outer);
477        sort_comments(&mut self.inner);
478    }
479
480    /// Reattaches owned comments to a raw projection at their source-relative
481    /// positions.
482    #[doc(hidden)]
483    pub fn __apply_to(&self, output: &mut TokenStream) {
484        for comment in self.outer.iter().rev().cloned() {
485            output.prepend_comment(comment);
486        }
487        for comment in self.inner.iter().cloned() {
488            output.insert_inner_comment(comment);
489        }
490    }
491}
492
493fn sort_comments(comments: &mut [Trivia]) {
494    comments.sort_by_key(|comment| comment.span().start().unwrap_or(usize::MAX));
495}
496
497fn take_stream_comments(stream: &mut TokenStream) -> Vec<Trivia> {
498    let mut comments = std::mem::take(&mut stream.1).into_vec();
499    for token in &mut stream.0 {
500        comments.extend(std::mem::take(token.leading_trivia_mut()).into_vec());
501        if let TokenTree::Group(group) = token {
502            comments.extend(take_stream_comments(group.stream_mut()));
503        }
504        comments.extend(std::mem::take(token.trailing_trivia_mut()).into_vec());
505    }
506    comments.extend(std::mem::take(&mut stream.2).into_vec());
507    comments
508}
509
510/// A typed terminal together with its adjacent comments.
511pub trait Terminal: Spanned {
512    /// Borrows the comments preceding this terminal.
513    fn leading_trivia(&self) -> &LeadingTrivia;
514
515    /// Mutably borrows the comments preceding this terminal.
516    fn leading_trivia_mut(&mut self) -> &mut LeadingTrivia;
517
518    /// Borrows the comments following this terminal.
519    fn trailing_trivia(&self) -> &TrailingTrivia;
520
521    /// Mutably borrows the comments following this terminal.
522    fn trailing_trivia_mut(&mut self) -> &mut TrailingTrivia;
523
524    /// Replaces the comments preceding this terminal.
525    fn set_leading_trivia(&mut self, trivia: impl IntoIterator<Item = Trivia>)
526    where
527        Self: Sized,
528    {
529        *self.leading_trivia_mut() = LeadingTrivia::new(trivia);
530    }
531
532    /// Replaces the comments and layout characters following this terminal.
533    fn set_trailing_trivia(&mut self, trivia: impl IntoIterator<Item = Trivia>)
534    where
535        Self: Sized,
536    {
537        *self.trailing_trivia_mut() = TrailingTrivia::new(trivia);
538    }
539}
540
541fn identifier_qualifier_spans(spelling: &str, span: &Span) -> (Option<Span>, Option<Span>) {
542    let separators = spelling
543        .match_indices('$')
544        .map(|(index, _)| index)
545        .collect::<Vec<_>>();
546    let source = separators.first().and_then(|separator| {
547        let name = &spelling[..*separator];
548        (!name.is_empty() && name.bytes().all(is_identifier_byte))
549            .then(|| span.subspan(0, separator + 1))
550    });
551    let index = separators.last().and_then(|separator| {
552        let digits = &spelling[separator + 1..];
553        (!digits.is_empty() && digits.bytes().all(|byte| byte.is_ascii_digit()))
554            .then(|| span.subspan(*separator, spelling.len()))
555    });
556    (source, index)
557}
558
559fn is_identifier_byte(byte: u8) -> bool {
560    byte == b'_' || byte.is_ascii_alphanumeric()
561}
562
563fn span_for_spelling(text: Arc<str>, span: Span) -> Span {
564    if span.text() == Some(text.as_ref()) {
565        span
566    } else {
567        let source = Source::with_file(span.file(), text);
568        let len = source.text().len();
569        Span::ranged(source, 0..len)
570    }
571}
572
573#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
574/// One raw M2 token tree.
575pub enum TokenTree {
576    /// A delimited group.
577    Group(TokenGroup),
578    /// A literal.
579    Literal(LiteralToken),
580    /// Punctuation.
581    Punct(Punct),
582    /// An identifier or keyword spelling.
583    Ident(IdentToken),
584}
585
586impl TokenTree {
587    /// Returns the token's source spelling when it is a flat lexical atom.
588    pub fn spelling(&self) -> Option<&str> {
589        match self {
590            Self::Literal(token) => Some(token.text()),
591            Self::Punct(token) => Some(token.text()),
592            Self::Ident(token) => Some(token.text()),
593            Self::Group(_) => None,
594        }
595    }
596
597    pub(crate) fn description(&self) -> String {
598        match self {
599            Self::Group(group) => group.delim_kind().to_string(),
600            token => token.spelling().unwrap_or("").to_owned(),
601        }
602    }
603
604    /// Borrows the comments attached before this atom.
605    pub fn leading_trivia(&self) -> &LeadingTrivia {
606        match self {
607            Self::Group(token) => token.leading_trivia(),
608            Self::Literal(token) => token.leading_trivia(),
609            Self::Punct(token) => token.leading_trivia(),
610            Self::Ident(token) => token.leading_trivia(),
611        }
612    }
613
614    /// Mutably borrows the comments attached before this atom.
615    pub fn leading_trivia_mut(&mut self) -> &mut LeadingTrivia {
616        match self {
617            Self::Group(token) => token.leading_trivia_mut(),
618            Self::Literal(token) => token.leading_trivia_mut(),
619            Self::Punct(token) => token.leading_trivia_mut(),
620            Self::Ident(token) => token.leading_trivia_mut(),
621        }
622    }
623
624    /// Borrows the comments attached after this atom.
625    pub fn trailing_trivia(&self) -> &TrailingTrivia {
626        match self {
627            Self::Group(token) => token.trailing_trivia(),
628            Self::Literal(token) => token.trailing_trivia(),
629            Self::Punct(token) => token.trailing_trivia(),
630            Self::Ident(token) => token.trailing_trivia(),
631        }
632    }
633
634    /// Mutably borrows the comments attached after this atom.
635    pub fn trailing_trivia_mut(&mut self) -> &mut TrailingTrivia {
636        match self {
637            Self::Group(token) => token.trailing_trivia_mut(),
638            Self::Literal(token) => token.trailing_trivia_mut(),
639            Self::Punct(token) => token.trailing_trivia_mut(),
640            Self::Ident(token) => token.trailing_trivia_mut(),
641        }
642    }
643}
644impl Lex for TokenTree {
645    fn to_tokens(&self, output: &mut TokenStream) {
646        output.push(self.clone());
647    }
648}
649
650#[derive(Debug, Clone, Default, PartialEq, Eq, Spanned)]
651/// An owned sequence of raw M2 token trees.
652pub struct TokenStream(Vec<TokenTree>, TrailingTrivia, LeadingTrivia, Option<Span>);
653
654impl TokenStream {
655    /// Creates an empty token stream.
656    pub fn new() -> Self {
657        Self::default()
658    }
659
660    /// Iterates over the stream's top-level token trees.
661    pub fn iter(&self) -> impl DoubleEndedIterator<Item = &TokenTree> + ExactSizeIterator {
662        self.0.iter()
663    }
664
665    /// Reports whether the stream contains no token trees.
666    pub fn is_empty(&self) -> bool {
667        self.0.is_empty()
668    }
669
670    pub(crate) fn len(&self) -> usize {
671        self.0.len()
672    }
673
674    pub(crate) fn get(&self, position: usize) -> Option<&TokenTree> {
675        self.0.get(position)
676    }
677
678    pub(crate) fn last(&self) -> Option<&TokenTree> {
679        self.0.last()
680    }
681
682    pub(crate) fn has_significant_tokens(&self) -> bool {
683        !self.0.is_empty()
684    }
685
686    pub(crate) fn has_trivia(&self) -> bool {
687        !self.1.is_empty() || !self.2.is_empty()
688    }
689
690    pub(crate) fn prefix_trivia(&self) -> &[Trivia] {
691        self.1.as_slice()
692    }
693
694    pub(crate) fn suffix_trivia(&self) -> &[Trivia] {
695        self.2.as_slice()
696    }
697
698    pub(crate) fn source(&self) -> Option<Arc<Source>> {
699        let mut source = self.3.as_ref().map(|span| Arc::clone(span.source()));
700        coherent_stream_source(self, &mut source)
701            .then_some(source)
702            .flatten()
703    }
704
705    pub(crate) fn set_physical_eof(&mut self, eof: Span) {
706        self.3 = Some(eof);
707    }
708
709    pub(crate) fn take_physical_eof(&mut self) -> Option<Span> {
710        self.3.take()
711    }
712
713    pub(crate) fn take_final_punctuation(
714        &mut self,
715        spelling: &str,
716    ) -> Option<(Punct, TrailingTrivia)> {
717        let position = self.0.len().checked_sub(1)?;
718        let TokenTree::Punct(punctuation) = self.0.get(position)? else {
719            return None;
720        };
721        if punctuation.text() != spelling {
722            return None;
723        }
724        let TokenTree::Punct(mut punctuation) = self.0.remove(position) else {
725            unreachable!("the final significant token was punctuation")
726        };
727        let trailing_trivia = std::mem::take(punctuation.trailing_trivia_mut());
728        Some((punctuation, trailing_trivia))
729    }
730
731    pub(crate) fn take_leading_trivia(&mut self) -> TrailingTrivia {
732        let mut trivia = std::mem::take(&mut self.1).into_vec();
733        trivia.extend(std::mem::take(&mut self.2).into_vec());
734        TrailingTrivia::new(trivia)
735    }
736
737    pub(crate) fn take_prefix_trivia(&mut self) -> TrailingTrivia {
738        std::mem::take(&mut self.1)
739    }
740
741    pub(crate) fn take_suffix_trivia(&mut self) -> LeadingTrivia {
742        std::mem::take(&mut self.2)
743    }
744
745    pub(crate) fn push(&mut self, mut token: TokenTree) {
746        if let Some(TokenTree::Group(group)) = self.0.last_mut()
747            && !group.delimiter().is_closed()
748        {
749            group.stream_mut().push(token);
750        } else {
751            token
752                .leading_trivia_mut()
753                .as_mut_vec()
754                .splice(..0, std::mem::take(&mut self.2).into_vec());
755            self.0.push(token);
756        }
757    }
758
759    pub(crate) fn push_line_comment(&mut self, comment: Trivia) {
760        if let Some(TokenTree::Group(group)) = self.0.last_mut()
761            && !group.delimiter().is_closed()
762        {
763            group.stream_mut().push_line_comment(comment);
764        } else if let Some(comment) = complete_line_comment(&comment) {
765            push_line_comment_block(self.2.as_mut_vec(), comment);
766        } else if let Some(token) = self.0.last_mut() {
767            token.trailing_trivia_mut().as_mut_vec().push(comment);
768        } else {
769            self.1.as_mut_vec().push(comment);
770        }
771    }
772
773    #[doc(hidden)]
774    pub fn push_leading_trivia(&mut self, trivia: Trivia) {
775        if let Some(TokenTree::Group(group)) = self.0.last_mut()
776            && !group.delimiter().is_closed()
777        {
778            group.stream_mut().push_leading_trivia(trivia);
779        } else {
780            self.2.as_mut_vec().push(trivia);
781        }
782    }
783
784    pub(crate) fn push_block_comment(&mut self, comment: Trivia) {
785        if let Some(TokenTree::Group(group)) = self.0.last_mut()
786            && !group.delimiter().is_closed()
787        {
788            group.stream_mut().push_block_comment(comment);
789        } else if let Some(token) = self.0.last_mut() {
790            token.trailing_trivia_mut().as_mut_vec().push(comment);
791        } else if !self.2.is_empty() {
792            self.2.as_mut_vec().push(comment);
793        } else {
794            self.1.as_mut_vec().push(comment);
795        }
796    }
797
798    pub(crate) fn push_trailing_trivia(&mut self, trivia: Trivia) {
799        if let Some(token) = self.0.last_mut() {
800            token.trailing_trivia_mut().as_mut_vec().push(trivia);
801        } else {
802            self.1.as_mut_vec().push(trivia);
803        }
804    }
805
806    pub(crate) fn complete_last_group(&mut self, kind: DelimiterKind, close: Span) -> bool {
807        let Some(TokenTree::Group(group)) = self.0.last_mut() else {
808            return false;
809        };
810        if group.stream.complete_last_group(kind, close.clone()) {
811            return true;
812        }
813        if group.delim_kind() != kind || group.delimiter().is_closed() {
814            return false;
815        }
816        group.delimiter.spans.complete(close);
817        true
818    }
819
820    pub(crate) fn last_innermost(&self) -> Option<&TokenTree> {
821        let last = self.last()?;
822        match last {
823            TokenTree::Group(group) if !group.delimiter().is_closed() => {
824                group.stream().last_innermost().or(Some(last))
825            }
826            _ => Some(last),
827        }
828    }
829
830    fn prepend_comment(&mut self, comment: Trivia) {
831        if let Some(first) = self.0.first_mut() {
832            first.leading_trivia_mut().as_mut_vec().insert(0, comment);
833        } else {
834            self.1.as_mut_vec().insert(0, comment);
835        }
836    }
837
838    fn insert_inner_comment(&mut self, comment: Trivia) {
839        let start = comment.span().start();
840        if let Some(start) = start {
841            for token in &mut self.0 {
842                if let TokenTree::Group(group) = token {
843                    let span = group.span();
844                    if span.shares_source(&comment.span())
845                        && span.start().is_some_and(|open| open <= start)
846                        && span.end().is_some_and(|close| start <= close)
847                    {
848                        group.stream_mut().insert_inner_comment(comment);
849                        return;
850                    }
851                }
852            }
853
854            if let Some(token) = self.0.iter_mut().rev().find(|token| {
855                let span = token.span();
856                span.shares_source(&comment.span())
857                    && span.start().is_some_and(|token_start| token_start <= start)
858            }) {
859                token.trailing_trivia_mut().as_mut_vec().push(comment);
860                return;
861            }
862
863            if self
864                .0
865                .iter()
866                .any(|token| token.span().shares_source(&comment.span()))
867            {
868                self.1.as_mut_vec().push(comment);
869                return;
870            }
871        }
872
873        if let Some(last) = self.0.last_mut() {
874            last.trailing_trivia_mut().as_mut_vec().push(comment);
875        } else {
876            self.1.as_mut_vec().push(comment);
877        }
878    }
879
880    #[doc(hidden)]
881    pub fn starts_with_whitespace(&self) -> bool {
882        false
883    }
884
885    #[doc(hidden)]
886    pub fn ends_with_whitespace(&self) -> bool {
887        false
888    }
889
890    #[doc(hidden)]
891    pub fn ends_with_line_break(&self) -> bool {
892        self.0
893            .last()
894            .is_some_and(|token| gap_after_contains(token, '\n'))
895    }
896
897    #[doc(hidden)]
898    pub fn ends_with_semicolon(&self) -> bool {
899        matches!(self.0.last(), Some(TokenTree::Punct(token)) if token.text() == ";")
900    }
901
902    /// Appends one emitted syntax fragment with any separator required to keep
903    /// adjacent word-like fragments lexically distinct.
904    ///
905    /// This is the composition operation used by [`crate::quote_m2!`]. The
906    /// fragment retains all of its internal token structure and comments.
907    /// Rendering inserts a conventional space when independently sourced atoms
908    /// would otherwise merge into one lexical token.
909    #[doc(hidden)]
910    pub fn append_fragment<T: Lex + ?Sized>(&mut self, fragment: &T) {
911        let fragment = fragment.to_token_stream();
912        self.extend([fragment]);
913    }
914
915    /// Removes and returns the final token tree, if any.
916    pub fn pop(&mut self) -> Option<TokenTree> {
917        self.0.pop()
918    }
919
920    /// Migrates source text from the shared sources retained by its spans.
921    pub fn to_source(&self) -> String {
922        self.to_string()
923    }
924}
925
926fn complete_line_comment(comment: &Trivia) -> Option<Trivia> {
927    let span = comment.span();
928    let (Some(start), Some(end)) = (span.start(), span.end()) else {
929        return None;
930    };
931    let source = span.source();
932    let line_start = source.text()[..start]
933        .rfind('\n')
934        .map_or(0, |newline| newline + 1);
935    source.text()[line_start..start]
936        .bytes()
937        .all(|byte| matches!(byte, b' ' | b'\t' | b'\r'))
938        .then(|| {
939            Trivia::from_span(
940                TriviaKind::LineComment,
941                Span::ranged(Arc::clone(source), line_start..end),
942            )
943        })
944}
945
946fn push_line_comment_block(comments: &mut Vec<Trivia>, comment: Trivia) {
947    let Some(previous) = comments.last_mut() else {
948        comments.push(comment);
949        return;
950    };
951    if previous.kind() != TriviaKind::LineComment || !previous.span().shares_source(&comment.span())
952    {
953        comments.push(comment);
954        return;
955    }
956    let (Some(previous_start), Some(previous_end), Some(comment_start), Some(comment_end)) = (
957        previous.span().start(),
958        previous.span().end(),
959        comment.span().start(),
960        comment.span().end(),
961    ) else {
962        comments.push(comment);
963        return;
964    };
965    let previous_span = previous.span();
966    let gap = &previous_span.source().text()[previous_end..comment_start];
967    let same_block = gap
968        .strip_prefix("\r\n")
969        .or_else(|| gap.strip_prefix('\n'))
970        .is_some_and(|indent| indent.bytes().all(|byte| matches!(byte, b' ' | b'\t')));
971    if same_block {
972        *previous = Trivia::from_span(
973            TriviaKind::LineComment,
974            Span::ranged(
975                Arc::clone(previous.span().source()),
976                previous_start..comment_end,
977            ),
978        );
979    } else {
980        comments.push(comment);
981    }
982}
983
984fn coherent_stream_source(stream: &TokenStream, source: &mut Option<Arc<Source>>) -> bool {
985    for trivia in stream.prefix_trivia().iter().chain(stream.suffix_trivia()) {
986        if !record_source(trivia.span(), source) {
987            return false;
988        }
989    }
990    for token in stream.iter() {
991        if !record_source(token.span(), source)
992            || !token
993                .leading_trivia()
994                .as_slice()
995                .iter()
996                .chain(token.trailing_trivia().as_slice())
997                .all(|trivia| record_source(trivia.span(), source))
998        {
999            return false;
1000        }
1001        if let TokenTree::Group(group) = token
1002            && !coherent_stream_source(group.stream(), source)
1003        {
1004            return false;
1005        }
1006    }
1007    true
1008}
1009
1010fn record_source(span: Span, source: &mut Option<Arc<Source>>) -> bool {
1011    match source {
1012        Some(expected) => Arc::ptr_eq(expected, span.source()),
1013        None => {
1014            *source = Some(Arc::clone(span.source()));
1015            true
1016        }
1017    }
1018}
1019
1020impl Display for TokenStream {
1021    fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
1022        write_stream(formatter, self)
1023    }
1024}
1025fn needs_separator(left: &TokenTree, right: &TokenTree) -> bool {
1026    let left_span = left.span();
1027    let right_span = right.span();
1028    if left_span.shares_source(&right_span) && left_span.end() == right_span.start() {
1029        return false;
1030    }
1031    let wordlike = |tree: &TokenTree| {
1032        matches!(
1033            tree,
1034            TokenTree::Ident(_) | TokenTree::Literal(_) | TokenTree::Group(_)
1035        )
1036    };
1037    (wordlike(left) && wordlike(right))
1038        || matches!((left, right), (TokenTree::Punct(left), TokenTree::Punct(right))
1039            if punctuation_would_merge(left.text(), right.text()))
1040}
1041
1042fn write_stream(formatter: &mut Formatter<'_>, stream: &TokenStream) -> Result {
1043    let mut previous_span = write_trivia(formatter, None, stream.1.as_slice())?;
1044    let mut previous_atom = None::<&TokenTree>;
1045    for tree in &stream.0 {
1046        if !tree.leading_trivia().is_empty() {
1047            previous_span =
1048                write_trivia(formatter, previous_span, tree.leading_trivia().as_slice())?;
1049            previous_atom = None;
1050        }
1051        if let Some(left) = previous_span {
1052            let recovered_space = write_source_spaces(formatter, left, tree.span())?;
1053            if !recovered_space && previous_atom.is_some_and(|left| needs_separator(left, tree)) {
1054                formatter.write_str(" ")?;
1055            }
1056        }
1057        write_tree(formatter, tree)?;
1058        previous_span = Some(tree.span());
1059        previous_atom = Some(tree);
1060        if !tree.trailing_trivia().is_empty() {
1061            previous_span =
1062                write_trivia(formatter, previous_span, tree.trailing_trivia().as_slice())?;
1063            previous_atom = None;
1064        }
1065    }
1066    write_trivia(formatter, previous_span, stream.2.as_slice())?;
1067    Ok(())
1068}
1069
1070fn write_trivia(
1071    formatter: &mut Formatter<'_>,
1072    mut previous: Option<Span>,
1073    trivia: &[Trivia],
1074) -> std::result::Result<Option<Span>, std::fmt::Error> {
1075    for item in trivia {
1076        if let Some(left) = previous {
1077            write_source_spaces(formatter, left, item.span())?;
1078        }
1079        formatter.write_str(item.text())?;
1080        previous = Some(item.span());
1081    }
1082    Ok(previous)
1083}
1084
1085fn write_source_spaces(
1086    formatter: &mut Formatter<'_>,
1087    left: Span,
1088    right: Span,
1089) -> std::result::Result<bool, std::fmt::Error> {
1090    if !left.shares_source(&right) {
1091        return Ok(false);
1092    }
1093    let (Some(end), Some(start)) = (left.end(), right.start()) else {
1094        return Ok(false);
1095    };
1096    if end > start {
1097        return Ok(false);
1098    }
1099    let gap = &left.source().text()[end..start];
1100    if gap.bytes().all(|byte| byte.is_ascii_whitespace()) {
1101        formatter.write_str(gap)?;
1102        Ok(true)
1103    } else {
1104        Ok(false)
1105    }
1106}
1107
1108fn write_tree(formatter: &mut Formatter<'_>, tree: &TokenTree) -> Result {
1109    match tree {
1110        TokenTree::Group(group) => {
1111            formatter.write_str(group.delim_kind().opening())?;
1112            let opening = group.delimiter().opening_span();
1113            if let Some(first) = group.stream.iter().next() {
1114                write_source_spaces(formatter, opening.clone(), first.span())?;
1115            }
1116            write_stream(formatter, &group.stream)?;
1117            if let Some(closing) = group.delimiter().closing_span() {
1118                let left = group
1119                    .stream
1120                    .iter()
1121                    .next_back()
1122                    .map_or(opening, Spanned::span);
1123                write_source_spaces(formatter, left, closing)?;
1124                formatter.write_str(group.delim_kind().closing())?;
1125            }
1126            Ok(())
1127        }
1128        TokenTree::Literal(literal) => formatter.write_str(literal.text()),
1129        TokenTree::Punct(punct) => formatter.write_str(punct.text()),
1130        TokenTree::Ident(ident) => formatter.write_str(ident.text()),
1131    }
1132}
1133
1134fn gap_after_contains(token: &TokenTree, character: char) -> bool {
1135    let span = token
1136        .trailing_trivia()
1137        .as_slice()
1138        .last()
1139        .map_or_else(|| token.span(), Spanned::span);
1140    let Some(end) = span.end() else {
1141        return false;
1142    };
1143    span.source().text()[end..].contains(character)
1144}
1145
1146/// Appends anything that can emit tokens, one item at a time.
1147///
1148/// `Lex` already states which types produce tokens; this states how a
1149/// `TokenStream` accepts them, by forwarding to `Lex::to_tokens`. It
1150/// subsumes the two concrete impls this replaced (`TokenTree` and
1151/// `TokenStream` itself both implement `Lex`), and works for any other `Lex`
1152/// type without a bespoke impl.
1153impl<T: Lex> Extend<T> for TokenStream {
1154    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1155        for item in iter {
1156            item.to_tokens(self);
1157        }
1158    }
1159}
1160
1161impl FromIterator<TokenTree> for TokenStream {
1162    fn from_iter<T: IntoIterator<Item = TokenTree>>(iter: T) -> Self {
1163        Self(
1164            iter.into_iter().collect(),
1165            TrailingTrivia::default(),
1166            LeadingTrivia::default(),
1167            None,
1168        )
1169    }
1170}
1171
1172impl IntoIterator for TokenStream {
1173    type Item = TokenTree;
1174    type IntoIter = IntoIter<TokenTree>;
1175    fn into_iter(self) -> Self::IntoIter {
1176        self.0.into_iter()
1177    }
1178}
1179
1180impl Lex for TokenStream {
1181    fn to_tokens(&self, output: &mut TokenStream) {
1182        let preserve_eof = output.0.is_empty() && output.1.is_empty() && output.2.is_empty();
1183        for trivia in self.1.as_slice().iter().cloned() {
1184            output.push_trailing_trivia(trivia);
1185        }
1186        for token in self.0.iter().cloned() {
1187            output.push(token);
1188        }
1189        output
1190            .2
1191            .as_mut_vec()
1192            .extend(self.2.as_slice().iter().cloned());
1193        output.3 = preserve_eof.then(|| self.3.clone()).flatten();
1194    }
1195}
1196
1197/// Emits a typed or raw syntax value into the shared token representation.
1198pub trait Lex {
1199    /// Appends this value's token trees to `output`.
1200    fn to_tokens(&self, output: &mut TokenStream);
1201
1202    /// Emits this value into a fresh token stream.
1203    fn to_token_stream(&self) -> TokenStream {
1204        let mut output = TokenStream::new();
1205        self.to_tokens(&mut output);
1206        output
1207    }
1208
1209    /// Renders this value as normalized Macaulay2 source.
1210    fn to_m2(&self) -> String {
1211        self.to_token_stream().to_source()
1212    }
1213}
1214
1215impl<T: Lex + ?Sized> Lex for &T {
1216    fn to_tokens(&self, output: &mut TokenStream) {
1217        (*self).to_tokens(output);
1218    }
1219}
1220
1221impl<T: Lex + ?Sized> Lex for Box<T> {
1222    fn to_tokens(&self, output: &mut TokenStream) {
1223        self.as_ref().to_tokens(output);
1224    }
1225}
1226
1227impl<T: Lex> Lex for Option<T> {
1228    fn to_tokens(&self, output: &mut TokenStream) {
1229        if let Some(value) = self {
1230            value.to_tokens(output);
1231        }
1232    }
1233}
1234
1235impl<T: Lex> Lex for [T] {
1236    fn to_tokens(&self, output: &mut TokenStream) {
1237        for token in self {
1238            token.to_tokens(output);
1239        }
1240    }
1241}
1242
1243impl<T: Lex> Lex for Vec<T> {
1244    fn to_tokens(&self, output: &mut TokenStream) {
1245        self.as_slice().to_tokens(output);
1246    }
1247}