1use std::error::Error;
38use std::fmt::{Display, Formatter, Result as FmtResult};
39use std::mem::take;
40use std::ops::Deref;
41use std::slice::Iter;
42use std::sync::Arc;
43use std::vec::IntoIter;
44
45use crate::lexer::{canonical_word_spelling, is_quote_specifier, newline_ends_cell};
46use crate::token_stream::TokenStreamParts;
47use crate::{
48 Delimiter, DelimiterKind, IdentToken, LeadingTrivia, Lex, LiteralToken, Punct, Source, Span,
49 Spanned, TOKEN_PARSE_RULES, Terminal, TokenGroup, TokenParseRule, TokenStream, TokenTree,
50 TrailingTrivia, Trivia,
51};
52
53#[derive(Debug, Clone, Default)]
54struct CellTokenStreamData {
56 trees: Vec<CellTokenTree>,
58 prefix: TrailingTrivia,
60 suffix: LeadingTrivia,
62 source: Option<Arc<Source>>,
64}
65
66impl PartialEq for CellTokenStreamData {
67 fn eq(&self, other: &Self) -> bool {
68 self.trees == other.trees
69 && self.prefix == other.prefix
70 && self.suffix == other.suffix
71 && match (&self.source, &other.source) {
72 (Some(left), Some(right)) => Arc::ptr_eq(left, right),
73 (None, None) => true,
74 _ => false,
75 }
76 }
77}
78
79impl Eq for CellTokenStreamData {}
80
81#[derive(Debug, Clone, PartialEq, Eq)]
82pub enum CellTokenTree {
88 Group(CellTokenGroup),
90 Literal(LiteralToken),
92 Punct(Punct),
94 Ident(IdentToken),
96 Adj(Span),
98}
99
100impl CellTokenTree {
101 pub fn spelling(&self) -> Option<&str> {
103 match self {
104 Self::Group(_) => None,
105 Self::Literal(token) => Some(token.text()),
106 Self::Punct(token) => Some(token.text()),
107 Self::Ident(token) => Some(token.text()),
108 Self::Adj(_) => Some(""),
109 }
110 }
111
112 pub fn leading_trivia(&self) -> &[Trivia] {
114 match self {
115 Self::Group(token) => token.leading_trivia().as_slice(),
116 Self::Literal(token) => token.leading_trivia().as_slice(),
117 Self::Punct(token) => token.leading_trivia().as_slice(),
118 Self::Ident(token) => token.leading_trivia().as_slice(),
119 Self::Adj(_) => &[],
120 }
121 }
122
123 pub fn trailing_trivia(&self) -> &[Trivia] {
125 match self {
126 Self::Group(token) => token.trailing_trivia().as_slice(),
127 Self::Literal(token) => token.trailing_trivia().as_slice(),
128 Self::Punct(token) => token.trailing_trivia().as_slice(),
129 Self::Ident(token) => token.trailing_trivia().as_slice(),
130 Self::Adj(_) => &[],
131 }
132 }
133
134 fn from_augmented(tree: TokenTree) -> Self {
136 match tree {
137 TokenTree::Group(group) => Self::Group(CellTokenGroup::from_augmented(group)),
138 TokenTree::Literal(token) => Self::Literal(token),
139 TokenTree::Punct(token) if token.text().is_empty() => Self::Adj(token.expect_span()),
140 TokenTree::Punct(token) => Self::Punct(token),
141 TokenTree::Ident(token) => Self::Ident(token),
142 }
143 }
144
145 fn into_lexical(self) -> Option<TokenTree> {
147 match self {
148 Self::Group(group) => Some(TokenTree::Group(group.into_lexical())),
149 Self::Literal(token) => Some(TokenTree::Literal(token)),
150 Self::Punct(token) => Some(TokenTree::Punct(token)),
151 Self::Ident(token) => Some(TokenTree::Ident(token)),
152 Self::Adj(_) => None,
153 }
154 }
155
156 fn into_parser_token(self) -> TokenTree {
158 match self {
159 Self::Group(group) => TokenTree::Group(group.into_parser_group()),
160 Self::Literal(token) => TokenTree::Literal(token),
161 Self::Punct(token) => TokenTree::Punct(token),
162 Self::Ident(token) => TokenTree::Ident(token),
163 Self::Adj(span) => TokenTree::Punct(Punct::from_span(span)),
164 }
165 }
166}
167
168impl Spanned for CellTokenTree {
169 fn try_span(&self) -> Option<Span> {
170 match self {
171 Self::Group(token) => token.try_span(),
172 Self::Literal(token) => token.try_span(),
173 Self::Punct(token) => token.try_span(),
174 Self::Ident(token) => token.try_span(),
175 Self::Adj(span) => Some(span.clone()),
176 }
177 }
178}
179
180#[derive(Debug, Clone, PartialEq, Eq)]
181pub struct CellTokenGroup {
183 delimiter: Delimiter,
185 stream: CellTokenStream,
187 leading_trivia: LeadingTrivia,
189 trailing_trivia: TrailingTrivia,
191}
192
193impl CellTokenGroup {
194 pub fn delimiter(&self) -> &Delimiter {
196 &self.delimiter
197 }
198
199 pub fn delim_kind(&self) -> DelimiterKind {
201 self.delimiter.kind
202 }
203
204 pub fn stream(&self) -> &CellTokenStream {
206 &self.stream
207 }
208
209 pub fn into_stream(self) -> CellTokenStream {
211 self.stream
212 }
213
214 fn from_augmented(group: TokenGroup) -> Self {
216 let (delimiter, stream, leading_trivia, trailing_trivia) = group.into_parts();
217 Self {
218 delimiter,
219 stream: CellTokenStream::from_augmented(stream),
220 leading_trivia,
221 trailing_trivia,
222 }
223 }
224
225 fn into_lexical(self) -> TokenGroup {
227 TokenGroup::from_parts(
228 self.delimiter,
229 self.stream.into_token_stream(),
230 self.leading_trivia,
231 self.trailing_trivia,
232 )
233 }
234
235 fn into_parser_group(self) -> TokenGroup {
237 TokenGroup::from_parts(
238 self.delimiter,
239 self.stream.into_parser_token_stream(),
240 self.leading_trivia,
241 self.trailing_trivia,
242 )
243 }
244}
245
246impl Spanned for CellTokenGroup {
247 fn try_span(&self) -> Option<Span> {
248 self.delimiter.try_span()
249 }
250}
251
252impl Terminal for CellTokenGroup {
253 fn leading_trivia(&self) -> &LeadingTrivia {
254 &self.leading_trivia
255 }
256
257 fn leading_trivia_mut(&mut self) -> &mut LeadingTrivia {
258 &mut self.leading_trivia
259 }
260
261 fn trailing_trivia(&self) -> &TrailingTrivia {
262 &self.trailing_trivia
263 }
264
265 fn trailing_trivia_mut(&mut self) -> &mut TrailingTrivia {
266 &mut self.trailing_trivia
267 }
268}
269
270#[derive(Debug, Clone, Default, PartialEq, Eq)]
271pub struct CellTokenStream(Arc<CellTokenStreamData>);
282
283impl CellTokenStream {
284 pub fn fork(&self) -> Self {
288 self.clone()
289 }
290
291 pub fn into_token_stream(self) -> TokenStream {
296 let CellTokenStreamData {
297 trees,
298 prefix,
299 suffix,
300 source,
301 } = self.into_data();
302 TokenStream::from_parts(TokenStreamParts {
303 trees: trees
304 .into_iter()
305 .filter_map(CellTokenTree::into_lexical)
306 .collect(),
307 prefix,
308 suffix,
309 source,
310 })
311 }
312
313 pub fn to_token_stream(&self) -> TokenStream {
317 self.clone().into_token_stream()
318 }
319
320 fn data(&self) -> &CellTokenStreamData {
322 &self.0
323 }
324
325 fn into_data(self) -> CellTokenStreamData {
327 Arc::try_unwrap(self.0).unwrap_or_else(|data| (*data).clone())
328 }
329
330 pub(crate) fn from_augmented(tokens: TokenStream) -> Self {
332 let TokenStreamParts {
333 trees,
334 prefix,
335 suffix,
336 source,
337 } = tokens.into_parts();
338 Self(Arc::new(CellTokenStreamData {
339 trees: trees
340 .into_iter()
341 .map(CellTokenTree::from_augmented)
342 .collect(),
343 prefix,
344 suffix,
345 source,
346 }))
347 }
348
349 pub(crate) fn source(&self) -> Option<Arc<Source>> {
351 self.data().source.clone().or_else(|| {
352 self.iter()
353 .find_map(Spanned::try_span)
354 .map(|span| Arc::clone(span.source()))
355 })
356 }
357
358 #[cfg(test)]
359 pub(crate) fn shares_storage(&self, other: &Self) -> bool {
360 Arc::ptr_eq(&self.0, &other.0)
361 }
362
363 pub(crate) fn into_parser_token_stream(self) -> TokenStream {
368 let CellTokenStreamData {
369 trees,
370 prefix,
371 suffix,
372 source,
373 } = self.into_data();
374 let mut tokens = TokenStream::from_parts(TokenStreamParts {
375 trees: trees
376 .into_iter()
377 .map(CellTokenTree::into_parser_token)
378 .collect(),
379 prefix,
380 suffix,
381 source,
382 });
383 tokens.settle_trivia();
384 tokens
385 }
386
387 pub(crate) fn from_framed_cells(cells: impl IntoIterator<Item = CellTokenStream>) -> Self {
389 let mut tokens = TokenStream::new();
390 for cell in cells {
391 tokens.extend([cell.into_parser_token_stream()]);
392 }
393 Self::from_augmented(tokens)
394 }
395}
396
397impl Deref for CellTokenStream {
398 type Target = [CellTokenTree];
399
400 fn deref(&self) -> &Self::Target {
401 &self.data().trees
402 }
403}
404
405impl AsRef<[CellTokenTree]> for CellTokenStream {
406 fn as_ref(&self) -> &[CellTokenTree] {
407 self
408 }
409}
410
411impl Spanned for CellTokenStream {
412 fn try_span(&self) -> Option<Span> {
413 Span::join_all(
414 self.data()
415 .prefix
416 .try_span()
417 .into_iter()
418 .chain(self.iter().filter_map(Spanned::try_span))
419 .chain(self.data().suffix.try_span()),
420 )
421 }
422}
423
424impl Display for CellTokenStream {
425 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
426 self.to_token_stream().fmt(formatter)
427 }
428}
429
430impl IntoIterator for CellTokenStream {
431 type Item = CellTokenTree;
432 type IntoIter = IntoIter<CellTokenTree>;
433
434 fn into_iter(self) -> Self::IntoIter {
435 self.into_data().trees.into_iter()
436 }
437}
438
439impl<'syntax> IntoIterator for &'syntax CellTokenStream {
440 type Item = &'syntax CellTokenTree;
441 type IntoIter = Iter<'syntax, CellTokenTree>;
442
443 fn into_iter(self) -> Self::IntoIter {
444 self.iter()
445 }
446}
447
448#[derive(Debug, Clone, Default)]
449struct CellStreamData {
450 cells: Vec<CellTokenStream>,
451 source: Option<Arc<Source>>,
452 bof: Option<Span>,
454 eof: Option<Span>,
456}
457
458#[derive(Debug, Clone, Default)]
459pub struct CellStream(Arc<CellStreamData>);
471
472impl PartialEq for CellStream {
473 fn eq(&self, other: &Self) -> bool {
474 self.as_ref() == other.as_ref()
475 }
476}
477
478impl Eq for CellStream {}
479
480impl Deref for CellStream {
481 type Target = [CellTokenStream];
482
483 fn deref(&self) -> &Self::Target {
484 &self.data().cells
485 }
486}
487
488impl AsRef<[CellTokenStream]> for CellStream {
489 fn as_ref(&self) -> &[CellTokenStream] {
490 self
491 }
492}
493
494impl CellStream {
495 pub fn new(tokens: TokenStream) -> Result<Self, CellStreamError> {
509 let source = tokens.source();
510 let bof = leading_layout_span(source.as_ref());
511 let eof = trailing_layout_span(source.as_ref());
512 let FramedCells { cells, incomplete } = frame_recovering(tokens);
513 match incomplete {
514 Some(tokens) => Err(CellStreamError {
515 span: end_span(&tokens),
516 }),
517 None => Ok(Self(Arc::new(CellStreamData {
518 cells,
519 source,
520 bof,
521 eof,
522 }))),
523 }
524 }
525
526 pub fn from_cells(cells: impl IntoIterator<Item = CellTokenStream>) -> Self {
532 Self::from_cells_with_source(cells, None)
533 }
534
535 pub(crate) fn from_cells_with_source(
537 cells: impl IntoIterator<Item = CellTokenStream>,
538 source: Option<Arc<Source>>,
539 ) -> Self {
540 Self(Arc::new(CellStreamData {
541 cells: cells.into_iter().collect(),
542 bof: leading_layout_span(source.as_ref()),
543 eof: trailing_layout_span(source.as_ref()),
544 source,
545 }))
546 }
547
548 pub fn fork(&self) -> Self {
555 self.clone()
556 }
557
558 fn data(&self) -> &CellStreamData {
560 &self.0
561 }
562
563 fn data_mut(&mut self) -> &mut CellStreamData {
565 Arc::make_mut(&mut self.0)
566 }
567
568 fn into_data(self) -> CellStreamData {
570 Arc::try_unwrap(self.0).unwrap_or_else(|data| (*data).clone())
571 }
572
573 pub fn into_token_stream(self) -> TokenStream {
579 let source = self.complete_source();
580 let mut tokens = flatten_cells(self.into_data().cells);
581 if let Some(source) = source {
582 tokens.set_source(source);
583 }
584 tokens
585 }
586
587 pub fn to_token_stream(&self) -> TokenStream {
592 let mut tokens = flatten_cells(self.iter().cloned());
593 if let Some(source) = self.complete_source() {
594 tokens.set_source(source);
595 }
596 tokens
597 }
598
599 pub(crate) fn complete_source(&self) -> Option<Arc<Source>> {
601 let source = self.data().source.as_ref()?;
602 let mut cursor = 0;
603 for cell in self {
604 if !covers_stream(cell, source, &mut cursor) {
605 return None;
606 }
607 }
608 source.text()[cursor..]
609 .bytes()
610 .all(|byte| byte.is_ascii_whitespace())
611 .then(|| Arc::clone(source))
612 }
613
614 pub(crate) fn physical_bof(&self) -> Span {
621 if let Some(source) = self.complete_source() {
622 let leading = source.leading_whitespace();
623 return Span::ranged(Arc::clone(&source), leading);
624 }
625 self.first()
626 .and_then(cell_first_span)
627 .and_then(|span| span.start().map(|start| span.at(start)))
628 .unwrap_or_else(|| Span::for_text(""))
629 }
630
631 pub(crate) fn physical_eof(&self) -> Span {
638 if let Some(source) = self.complete_source() {
639 let trailing = source.trailing_whitespace();
640 return Span::ranged(Arc::clone(&source), trailing);
641 }
642 self.last().map_or_else(|| Span::for_text(""), end_span)
643 }
644
645 pub(crate) fn from_source_file(source_file: &crate::SourceFile) -> Self {
647 let mut cells = source_file
648 .cells
649 .iter()
650 .map(Lex::to_token_stream)
651 .collect::<Vec<_>>();
652 for (index, comments) in [
653 (0, &source_file.leading_trivia),
654 (cells.len(), source_file.eof.leading_trivia()),
655 ]
656 .into_iter()
657 .rev()
658 {
659 if !comments.is_empty() {
660 let mut comment_cell = TokenStream::new();
661 comment_cell.extend(comments.as_slice().iter().cloned());
662 cells.insert(index, comment_cell);
663 }
664 }
665 Self(Arc::new(CellStreamData {
666 cells: cells
667 .into_iter()
668 .map(CellTokenStream::from_augmented)
669 .collect(),
670 source: None,
671 bof: source_file.bof.try_span(),
672 eof: source_file.eof.try_span(),
673 }))
674 }
675}
676
677fn covers_stream(stream: &CellTokenStream, source: &Arc<Source>, cursor: &mut usize) -> bool {
679 for trivia in stream.data().prefix.as_slice() {
680 if !covers_span(trivia.span(), source, cursor) {
681 return false;
682 }
683 }
684 for token in stream.iter() {
685 for trivia in token.leading_trivia() {
686 if !covers_span(trivia.span(), source, cursor) {
687 return false;
688 }
689 }
690 let covered = match token {
691 CellTokenTree::Group(group) => {
692 covers_span(group.delimiter().opening_span(), source, cursor)
693 && covers_stream(group.stream(), source, cursor)
694 && group
695 .delimiter()
696 .closing_span()
697 .is_none_or(|span| covers_span(span, source, cursor))
698 }
699 _ => covers_span(token.span(), source, cursor),
700 };
701 if !covered {
702 return false;
703 }
704 for trivia in token.trailing_trivia() {
705 if !covers_span(trivia.span(), source, cursor) {
706 return false;
707 }
708 }
709 }
710 stream
711 .data()
712 .suffix
713 .as_slice()
714 .iter()
715 .all(|trivia| covers_span(trivia.span(), source, cursor))
716}
717
718fn covers_span(span: Span, source: &Arc<Source>, cursor: &mut usize) -> bool {
720 if !Arc::ptr_eq(span.source(), source) {
721 return false;
722 }
723 let (Some(start), Some(end)) = (span.start(), span.end()) else {
724 return false;
725 };
726 if start == end {
727 return start >= *cursor;
728 }
729 if start < *cursor
730 || !source.text()[*cursor..start]
731 .bytes()
732 .all(|byte| byte.is_ascii_whitespace())
733 {
734 return false;
735 }
736 *cursor = end;
737 true
738}
739
740impl Display for CellStream {
741 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
742 write_leading_layout(
743 formatter,
744 self.data().bof.as_ref(),
745 self.first().and_then(cell_first_span).as_ref(),
746 )?;
747 let mut previous: Option<Span> = None;
748 for (index, cell) in self.iter().enumerate() {
749 if index != 0 {
750 let next = cell_first_span(cell);
751 let mut recovered = false;
752 if let Some((left, right)) = previous.as_ref().zip(next.as_ref())
753 && left.shares_source(right)
754 && let (Some(end), Some(start)) = (left.end(), right.start())
755 && end <= start
756 {
757 let gap = &left.source().text()[end..start];
758 let written = !gap.is_empty() || !left.source().file().is_synthetic();
761 if written && gap.bytes().all(|byte| byte.is_ascii_whitespace()) {
762 formatter.write_str(gap)?;
763 recovered = true;
764 }
765 }
766 if !recovered {
767 formatter.write_str("\n")?;
768 }
769 }
770 cell.fmt(formatter)?;
771 previous = cell_last_span(cell);
772 }
773 write_trailing_layout(formatter, self.data().eof.as_ref(), previous.as_ref())
774 }
775}
776
777fn leading_layout_span(source: Option<&Arc<Source>>) -> Option<Span> {
779 source.map(|source| Span::ranged(Arc::clone(source), source.leading_whitespace()))
780}
781
782fn write_leading_layout(
789 formatter: &mut Formatter<'_>,
790 bof: Option<&Span>,
791 first_cell: Option<&Span>,
792) -> FmtResult {
793 let (Some(bof), Some(first)) = (bof, first_cell) else {
794 return Ok(());
795 };
796 if !first.shares_source(bof) {
797 return Ok(());
798 }
799 let Some((start, stop)) = bof.start().zip(first.start()) else {
800 return Ok(());
801 };
802 match bof.source().text().get(start..stop) {
803 Some(prefix) if prefix.bytes().all(|byte| byte.is_ascii_whitespace()) => {
804 formatter.write_str(prefix)
805 }
806 _ => Ok(()),
807 }
808}
809
810fn trailing_layout_span(source: Option<&Arc<Source>>) -> Option<Span> {
812 source.map(|source| Span::ranged(Arc::clone(source), source.trailing_whitespace()))
813}
814
815fn write_trailing_layout(
821 formatter: &mut Formatter<'_>,
822 eof: Option<&Span>,
823 last_cell: Option<&Span>,
824) -> FmtResult {
825 let Some(eof) = eof else {
826 return Ok(());
827 };
828 let resume = match last_cell {
829 Some(last) if last.shares_source(eof) => last.end(),
830 Some(_) => return Ok(()),
831 None => eof.start(),
832 };
833 let Some((resume, stop)) = resume.zip(eof.end()) else {
834 return Ok(());
835 };
836 match eof.source().text().get(resume..stop) {
837 Some(suffix) if suffix.bytes().all(|byte| byte.is_ascii_whitespace()) => {
838 formatter.write_str(suffix)
839 }
840 _ => Ok(()),
841 }
842}
843
844fn cell_first_span(tokens: &CellTokenStream) -> Option<Span> {
846 tokens
847 .data()
848 .prefix
849 .as_slice()
850 .first()
851 .map(Spanned::span)
852 .or_else(|| {
853 tokens.iter().next().map(|token| {
854 token
855 .leading_trivia()
856 .first()
857 .map_or_else(|| token.span(), Spanned::span)
858 })
859 })
860 .or_else(|| tokens.data().suffix.as_slice().first().map(Spanned::span))
861}
862
863fn cell_last_span(tokens: &CellTokenStream) -> Option<Span> {
865 tokens
866 .data()
867 .suffix
868 .as_slice()
869 .last()
870 .map(Spanned::span)
871 .or_else(|| tokens.iter().next_back().map(token_end_span))
872 .or_else(|| tokens.data().prefix.as_slice().last().map(Spanned::span))
873}
874
875impl IntoIterator for CellStream {
876 type Item = CellTokenStream;
877 type IntoIter = IntoIter<CellTokenStream>;
878
879 fn into_iter(self) -> Self::IntoIter {
880 self.into_data().cells.into_iter()
881 }
882}
883
884impl<'syntax> IntoIterator for &'syntax CellStream {
885 type Item = &'syntax CellTokenStream;
886 type IntoIter = Iter<'syntax, CellTokenStream>;
887
888 fn into_iter(self) -> Self::IntoIter {
889 self.iter()
890 }
891}
892
893impl FromIterator<CellTokenStream> for CellStream {
894 fn from_iter<T: IntoIterator<Item = CellTokenStream>>(iter: T) -> Self {
895 Self::from_cells(iter)
896 }
897}
898
899fn flatten_cells(cells: impl IntoIterator<Item = CellTokenStream>) -> TokenStream {
901 let mut output = TokenStream::new();
902 for cell in cells {
903 output.extend([cell.into_token_stream()]);
904 }
905 output
906}
907
908#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
909pub struct CellStreamError {
915 span: Span,
917}
918
919impl Display for CellStreamError {
920 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
921 formatter.write_str("input ends inside an incomplete cell")
922 }
923}
924
925impl Error for CellStreamError {}
926
927pub trait Tokenize {
953 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError>;
960
961 fn to_cell_stream(&self) -> Result<CellStream, CellStreamError> {
970 let mut output = CellStream::default();
971 self.tokenize(&mut output)?;
972 Ok(output)
973 }
974}
975
976impl Tokenize for TokenStream {
977 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError> {
978 let tokenized = CellStream::new(self.clone())?.into_data();
979 let output = output.data_mut();
980 if output.cells.is_empty() {
981 output.source = tokenized.source;
982 output.bof = tokenized.bof;
983 output.eof = tokenized.eof;
984 } else {
985 output.source = None;
986 output.eof = None;
987 }
988 output.cells.extend(tokenized.cells);
989 Ok(())
990 }
991}
992
993impl crate::SourceFile {
994 pub(crate) fn set_closing_comments(&mut self, comments: Vec<Trivia>) {
997 if self.cells.is_empty() {
998 self.leading_trivia = LeadingTrivia::new(comments);
999 } else {
1000 self.eof.set_leading_trivia(comments);
1001 }
1002 }
1003}
1004
1005impl Tokenize for crate::SourceFile {
1006 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError> {
1007 let tokenized = CellStream::from_source_file(self).into_data();
1008 let output = output.data_mut();
1009 if output.cells.is_empty() {
1010 output.bof = tokenized.bof;
1011 }
1012 output.eof = output.cells.is_empty().then_some(tokenized.eof).flatten();
1013 output.cells.extend(tokenized.cells);
1014 output.source = None;
1015 Ok(())
1016 }
1017}
1018
1019impl Tokenize for crate::ParsedFile {
1020 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError> {
1021 self.cst().tokenize(output)
1022 }
1023}
1024
1025impl<T: Tokenize + ?Sized> Tokenize for &T {
1026 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError> {
1027 (*self).tokenize(output)
1028 }
1029}
1030
1031#[derive(Debug, Clone, PartialEq, Eq)]
1041pub struct FramedCells {
1042 pub cells: Vec<CellTokenStream>,
1044 pub incomplete: Option<CellTokenStream>,
1046}
1047
1048pub fn frame_recovering(tokens: TokenStream) -> FramedCells {
1082 let mut tokens = tokens;
1083 let prefix_trivia = tokens.take_prefix_trivia();
1086 let suffix_trivia = tokens.take_suffix_trivia();
1087 let mut cells = Vec::new();
1088 let mut current = TokenStream::new();
1089 current.extend(prefix_trivia.into_vec());
1090 let mut pending_boundary = false;
1091 let mut quote_next = false;
1092
1093 for token in tokens {
1094 if pending_boundary {
1097 cells.push(insert_adjacency(take(&mut current)));
1098 pending_boundary = false;
1099 quote_next = false;
1100 } else if current
1101 .last()
1102 .is_some_and(|left| tokens_cross_line_break(left, &token))
1103 && newline_ends_cell(¤t)
1104 {
1105 cells.push(insert_adjacency(take(&mut current)));
1106 quote_next = false;
1107 }
1108
1109 let quoted = take(&mut quote_next);
1110 let quotes_next = !quoted
1111 && matches!(&token, TokenTree::Ident(identifier)
1112 if is_quote_specifier(canonical_word_spelling(identifier.text())));
1113 let semicolon = !quoted && token.spelling() == Some(";");
1114
1115 current.extend([token]);
1116 if semicolon {
1117 pending_boundary = true;
1118 }
1119 if quotes_next {
1120 quote_next = true;
1121 }
1122 }
1123
1124 current.extend(suffix_trivia.into_vec());
1125
1126 if pending_boundary {
1129 cells.push(insert_adjacency(current));
1130 return FramedCells {
1131 cells,
1132 incomplete: None,
1133 };
1134 }
1135
1136 if !has_syntax(¤t) {
1139 if current.has_trivia() {
1140 cells.push(CellTokenStream::from_augmented(current));
1141 }
1142 return FramedCells {
1143 cells,
1144 incomplete: None,
1145 };
1146 }
1147
1148 if !ends_in_incomplete_group(¤t) && newline_ends_cell(¤t) {
1151 cells.push(insert_adjacency(current));
1152 FramedCells {
1153 cells,
1154 incomplete: None,
1155 }
1156 } else {
1157 FramedCells {
1158 cells,
1159 incomplete: Some(insert_adjacency(current)),
1160 }
1161 }
1162}
1163
1164pub(crate) fn end_span(tokens: &CellTokenStream) -> Span {
1166 let ends_with_semicolon = ends_with_cell_semicolon(tokens);
1167 let span = tokens
1168 .iter()
1169 .next_back()
1170 .map(token_end_span)
1171 .or_else(|| tokens.data().suffix.as_slice().last().map(Spanned::span))
1172 .or_else(|| tokens.data().prefix.as_slice().last().map(Spanned::span));
1173 let Some(span) = span else {
1174 return Span::for_text("");
1175 };
1176 let Some(end) = span.end() else {
1177 return Span::unlocated(Arc::clone(span.source()));
1178 };
1179 if !ends_with_semicolon && let Some(newline) = span.source().text()[end..].find('\n') {
1180 return span.at(end + newline + 1);
1181 }
1182 span.at(end)
1183}
1184
1185fn token_end_span(token: &CellTokenTree) -> Span {
1187 if let Some(trivia) = token.trailing_trivia().last() {
1188 return trivia.span();
1189 }
1190 if let CellTokenTree::Group(group) = token
1191 && !group.delimiter().is_closed()
1192 {
1193 let contents = group.stream();
1194 if let Some(inner) = contents.iter().next_back() {
1195 return token_end_span(inner);
1196 }
1197 if let Some(trivia) = contents
1198 .data()
1199 .suffix
1200 .as_slice()
1201 .last()
1202 .or_else(|| contents.data().prefix.as_slice().last())
1203 {
1204 return trivia.span();
1205 }
1206 }
1207 token.span()
1208}
1209
1210pub(crate) fn ends_with_cell_semicolon(tokens: &CellTokenStream) -> bool {
1212 let mut quote_next = false;
1213 let mut final_semicolon = false;
1214 for token in tokens.iter() {
1215 let quoted = take(&mut quote_next);
1216 final_semicolon = !quoted && token.spelling() == Some(";");
1217 quote_next = !quoted
1218 && matches!(token, CellTokenTree::Ident(identifier)
1219 if is_quote_specifier(canonical_word_spelling(identifier.text())));
1220 }
1221 final_semicolon
1222}
1223
1224fn has_syntax(stream: &TokenStream) -> bool {
1226 !stream.is_empty()
1227}
1228
1229fn ends_in_incomplete_group(stream: &TokenStream) -> bool {
1231 matches!(stream.iter().next_back(), Some(TokenTree::Group(group)) if !group.delimiter().is_closed())
1232}
1233
1234fn insert_adjacency(mut tokens: TokenStream) -> CellTokenStream {
1236 let prefix = tokens.take_prefix_trivia();
1237 let suffix = tokens.take_suffix_trivia();
1238 let mut output = TokenStream::new();
1239 output.extend(prefix.into_vec());
1240 let mut left_can_end = false;
1241 let mut quote_next = false;
1242
1243 for mut token in tokens {
1244 if let TokenTree::Group(group) = &mut token {
1245 let contents = take(group.stream_mut());
1246 *group.stream_mut() = insert_adjacency(contents).into_parser_token_stream();
1247 }
1248
1249 let quoted = take(&mut quote_next);
1250 let crossed_newline = output
1251 .last()
1252 .is_some_and(|left| tokens_cross_line_break(left, &token));
1253 if left_can_end && !quoted && !crossed_newline && can_begin_implicit_operand(&token) {
1254 let span = token.expect_span().subspan(0, 0);
1255 output.extend([TokenTree::Punct(Punct::from_span(span))]);
1256 }
1257
1258 let quotes_next = !quoted
1259 && matches!(&token, TokenTree::Ident(identifier)
1260 if is_quote_specifier(canonical_word_spelling(identifier.text())));
1261 left_can_end = quoted || can_end_operand(&token);
1262 quote_next = quotes_next;
1263 output.extend([token]);
1264 }
1265 for trivia in suffix.into_vec() {
1266 output.push_leading_trivia(trivia);
1267 }
1268 CellTokenStream::from_augmented(output)
1269}
1270
1271fn tokens_cross_line_break(left: &TokenTree, right: &TokenTree) -> bool {
1273 let left = left.expect_span();
1274 let right = right.expect_span();
1275 if !left.shares_source(&right) {
1276 return false;
1277 }
1278 let (Some(end), Some(start)) = (left.end(), right.start()) else {
1279 return false;
1280 };
1281 end <= start && left.source().text()[end..start].contains('\n')
1282}
1283
1284fn token_parse_rule(token: &TokenTree) -> Option<TokenParseRule> {
1286 let spelling = token.spelling().map(canonical_word_spelling)?;
1287 TOKEN_PARSE_RULES
1288 .binary_search_by_key(&spelling, |(declared, _)| *declared)
1289 .ok()
1290 .map(|index| TOKEN_PARSE_RULES[index].1)
1291}
1292
1293fn can_begin_implicit_operand(token: &TokenTree) -> bool {
1295 match token_parse_rule(token) {
1296 Some(TokenParseRule::Prefix(_, _) | TokenParseRule::Unary(_, _)) => true,
1297 Some(_) => false,
1298 None => matches!(
1299 token,
1300 TokenTree::Ident(_) | TokenTree::Literal(_) | TokenTree::Group(_)
1301 ),
1302 }
1303}
1304
1305fn can_end_operand(token: &TokenTree) -> bool {
1307 match token_parse_rule(token) {
1308 Some(TokenParseRule::Postfix(_)) => true,
1309 Some(_) => false,
1310 None => matches!(
1311 token,
1312 TokenTree::Ident(_) | TokenTree::Literal(_) | TokenTree::Group(_)
1313 ),
1314 }
1315}
1316
1317#[cfg(test)]
1318mod tests {
1319 use super::{Arc, CellStream, frame_recovering};
1320 use crate::{
1321 CellTokenTree, CommentTrivia, Spanned, TokenTree, Tokenize, TriviaKind, lex_str,
1322 lex_str_recovering,
1323 };
1324
1325 #[test]
1326 fn recovering_framing_retains_completed_prefix_and_incomplete_tail() {
1327 let source = "a = 1\nf = x -> (";
1328 let recovered = lex_str_recovering(source).unwrap();
1329 let framed = frame_recovering(recovered.value);
1330
1331 assert_eq!(framed.cells.len(), 1);
1332 let completed = framed.cells[0].span();
1333 assert_eq!(completed.text(), Some("a = 1"));
1334 assert_eq!(completed.range(), Some(0..5));
1335 let tail = framed.incomplete.unwrap();
1336 assert_eq!(tail.span().text(), Some("f = x -> ("));
1337 assert_eq!(tail.span().range(), Some(6..source.len()));
1338 assert!(completed.shares_source(&tail.span()));
1339 }
1340
1341 #[test]
1342 fn recovering_framing_preserves_comments_in_both_parts() {
1343 let source = "-- complete\na = 1 -- retained\n-- incomplete\nf = x -> ( -- inside\n";
1344 let framed = frame_recovering(lex_str_recovering(source).unwrap().value);
1345 assert_eq!(framed.cells.len(), 1);
1346 let completed = &framed.cells[0];
1347 let tail = framed.incomplete.unwrap();
1348
1349 let comments = |cell: &super::CellTokenStream| {
1350 let comments = CommentTrivia::of(&cell.to_token_stream());
1351 comments
1352 .outer()
1353 .iter()
1354 .chain(comments.inner())
1355 .map(|trivia| {
1356 assert_eq!(trivia.span().text(), Some(trivia.text()));
1357 assert!(trivia.span().shares_source(&cell.span()));
1358 trivia.text().to_owned()
1359 })
1360 .collect::<Vec<_>>()
1361 };
1362 assert_eq!(comments(completed), ["-- complete", "-- retained"]);
1363 assert_eq!(comments(&tail), ["-- incomplete", "-- inside"]);
1364 assert_eq!(completed.span().text(), Some("a = 1"));
1365 assert_eq!(tail.span().text(), Some("f = x -> ("));
1366 }
1367
1368 #[test]
1369 fn recovering_framing_handles_complete_empty_and_trivia_only_input() {
1370 for (source, expected) in [
1371 ("a = 1; b = 2", vec!["a = 1;", "b = 2"]),
1372 ("", vec![]),
1373 (" \n ", vec![]),
1374 ("-- comment", vec!["-- comment"]),
1375 ] {
1376 let framed = frame_recovering(lex_str(source).unwrap());
1377 assert!(framed.incomplete.is_none(), "{source:?}");
1378 assert_eq!(
1379 framed
1380 .cells
1381 .iter()
1382 .map(ToString::to_string)
1383 .collect::<Vec<_>>(),
1384 expected,
1385 "{source:?}",
1386 );
1387 }
1388 }
1389
1390 fn count_cell_adjacency(tokens: &[CellTokenTree]) -> usize {
1391 tokens
1392 .iter()
1393 .map(|token| match token {
1394 CellTokenTree::Group(group) => count_cell_adjacency(group.stream()),
1395 CellTokenTree::Adj(_) => 1,
1396 _ => 0,
1397 })
1398 .sum()
1399 }
1400
1401 fn count_raw_adjacency(tokens: &[TokenTree]) -> usize {
1402 tokens
1403 .iter()
1404 .map(|token| match token {
1405 TokenTree::Group(group) => count_raw_adjacency(group.stream()),
1406 TokenTree::Punct(punctuation) if punctuation.text().is_empty() => 1,
1407 _ => 0,
1408 })
1409 .sum()
1410 }
1411
1412 #[test]
1413 fn cells_are_structural_partitions() {
1414 let cells = CellStream::new(lex_str("f \t-- note\n x").unwrap()).unwrap();
1415 assert_eq!(cells.len(), 2);
1416 assert_eq!(cells.to_string(), "f \t-- note\n x");
1417 }
1418
1419 #[test]
1420 fn same_line_application_gets_one_empty_punctuation() {
1421 let cells = lex_str("f x").unwrap().to_cell_stream().unwrap();
1422 assert_eq!(
1423 cells
1424 .iter()
1425 .flat_map(|cell| cell.iter())
1426 .filter(|token| matches!(token, CellTokenTree::Adj(_)))
1427 .count(),
1428 1,
1429 );
1430 }
1431
1432 #[test]
1433 fn flattening_a_framed_cell_restores_lexical_tokens() {
1434 let raw = lex_str("f (g x)").unwrap();
1435 assert_eq!(count_raw_adjacency(&raw), 0);
1436
1437 let cells = raw.to_cell_stream().unwrap();
1438 assert_eq!(count_cell_adjacency(&cells[0]), 2);
1439
1440 let raw = cells.into_token_stream();
1441 assert_eq!(count_raw_adjacency(&raw), 0);
1442 assert_eq!(raw.to_string(), "f (g x)");
1443 }
1444
1445 #[test]
1446 fn line_comment_blocks_begin_the_cell_on_their_right() {
1447 let cells = CellStream::new(lex_str("x\n-- first\n-- second\ny").unwrap()).unwrap();
1448 assert_eq!(cells.len(), 2);
1449 let comments = cells[1].iter().next().unwrap().leading_trivia();
1450 assert_eq!(comments.len(), 1);
1451 assert_eq!(comments[0].kind(), TriviaKind::LineComment);
1452 assert_eq!(comments[0].text(), "-- first\n-- second");
1453 }
1454
1455 #[test]
1456 fn a_blank_line_separates_outer_comment_blocks() {
1457 let cells = CellStream::new(lex_str("-- first\n\n-- second\ny").unwrap()).unwrap();
1458 let comments = cells[0].iter().next().unwrap().leading_trivia();
1459
1460 assert_eq!(comments.len(), 2);
1461 assert_eq!(comments[0].text(), "-- first");
1462 assert_eq!(comments[1].text(), "-- second");
1463 }
1464
1465 #[test]
1466 fn line_comments_do_not_split_an_incomplete_cell() {
1467 let cells = CellStream::new(lex_str("x + -- reason\ny").unwrap()).unwrap();
1468 assert_eq!(cells.len(), 1);
1469 assert!(cells[0].iter().any(|token| {
1470 token
1471 .trailing_trivia()
1472 .iter()
1473 .any(|trivia| trivia.kind() == TriviaKind::LineComment)
1474 }));
1475 }
1476
1477 #[test]
1478 fn fork_copies_only_the_modified_cell_path() {
1479 let original = CellStream::new(lex_str("left; right").unwrap()).unwrap();
1480 let mut fork = original.fork();
1481
1482 assert!(Arc::ptr_eq(&original.0, &fork.0));
1483
1484 fork.data_mut().cells.pop();
1485
1486 assert!(!Arc::ptr_eq(&original.0, &fork.0));
1487 assert_eq!(original.to_string(), "left; right");
1488 assert_eq!(fork.to_string(), "left;");
1489 assert!(original[0].shares_storage(&fork[0]));
1490 }
1491}