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
45#[cfg(feature = "tree-sitter")]
46use crate::CommentTrivia;
47use crate::lexer::{canonical_word_spelling, is_quote_specifier, newline_ends_cell};
48use crate::token_stream::TokenStreamParts;
49use crate::{
50 Delimiter, DelimiterKind, IdentToken, LeadingTrivia, Lex, LiteralToken, Punct, Source, Span,
51 Spanned, TOKEN_PARSE_RULES, Terminal, TokenGroup, TokenParseRule, TokenStream, TokenTree,
52 TrailingTrivia, Trivia,
53};
54
55#[derive(Debug, Clone, Default)]
56struct CellTokenStreamData {
58 trees: Vec<CellTokenTree>,
60 prefix: TrailingTrivia,
62 suffix: LeadingTrivia,
64 source: Option<Arc<Source>>,
66}
67
68impl PartialEq for CellTokenStreamData {
69 fn eq(&self, other: &Self) -> bool {
70 self.trees == other.trees
71 && self.prefix == other.prefix
72 && self.suffix == other.suffix
73 && match (&self.source, &other.source) {
74 (Some(left), Some(right)) => Arc::ptr_eq(left, right),
75 (None, None) => true,
76 _ => false,
77 }
78 }
79}
80
81impl Eq for CellTokenStreamData {}
82
83#[derive(Debug, Clone, PartialEq, Eq)]
84pub enum CellTokenTree {
90 Group(CellTokenGroup),
92 Literal(LiteralToken),
94 Punct(Punct),
96 Ident(IdentToken),
98 Adj(Span),
100}
101
102impl CellTokenTree {
103 pub fn spelling(&self) -> Option<&str> {
105 match self {
106 Self::Group(_) => None,
107 Self::Literal(token) => Some(token.text()),
108 Self::Punct(token) => Some(token.text()),
109 Self::Ident(token) => Some(token.text()),
110 Self::Adj(_) => Some(""),
111 }
112 }
113
114 pub fn leading_trivia(&self) -> &[Trivia] {
116 match self {
117 Self::Group(token) => token.leading_trivia().as_slice(),
118 Self::Literal(token) => token.leading_trivia().as_slice(),
119 Self::Punct(token) => token.leading_trivia().as_slice(),
120 Self::Ident(token) => token.leading_trivia().as_slice(),
121 Self::Adj(_) => &[],
122 }
123 }
124
125 pub fn trailing_trivia(&self) -> &[Trivia] {
127 match self {
128 Self::Group(token) => token.trailing_trivia().as_slice(),
129 Self::Literal(token) => token.trailing_trivia().as_slice(),
130 Self::Punct(token) => token.trailing_trivia().as_slice(),
131 Self::Ident(token) => token.trailing_trivia().as_slice(),
132 Self::Adj(_) => &[],
133 }
134 }
135
136 fn from_augmented(tree: TokenTree) -> Self {
138 match tree {
139 TokenTree::Group(group) => Self::Group(CellTokenGroup::from_augmented(group)),
140 TokenTree::Literal(token) => Self::Literal(token),
141 TokenTree::Punct(token) if token.text().is_empty() => Self::Adj(token.expect_span()),
142 TokenTree::Punct(token) => Self::Punct(token),
143 TokenTree::Ident(token) => Self::Ident(token),
144 }
145 }
146
147 fn into_lexical(self) -> Option<TokenTree> {
149 match self {
150 Self::Group(group) => Some(TokenTree::Group(group.into_lexical())),
151 Self::Literal(token) => Some(TokenTree::Literal(token)),
152 Self::Punct(token) => Some(TokenTree::Punct(token)),
153 Self::Ident(token) => Some(TokenTree::Ident(token)),
154 Self::Adj(_) => None,
155 }
156 }
157
158 fn into_parser_token(self) -> TokenTree {
160 match self {
161 Self::Group(group) => TokenTree::Group(group.into_parser_group()),
162 Self::Literal(token) => TokenTree::Literal(token),
163 Self::Punct(token) => TokenTree::Punct(token),
164 Self::Ident(token) => TokenTree::Ident(token),
165 Self::Adj(span) => TokenTree::Punct(Punct::from_span(span)),
166 }
167 }
168}
169
170impl Spanned for CellTokenTree {
171 fn try_span(&self) -> Option<Span> {
172 match self {
173 Self::Group(token) => token.try_span(),
174 Self::Literal(token) => token.try_span(),
175 Self::Punct(token) => token.try_span(),
176 Self::Ident(token) => token.try_span(),
177 Self::Adj(span) => Some(span.clone()),
178 }
179 }
180}
181
182#[derive(Debug, Clone, PartialEq, Eq)]
183pub struct CellTokenGroup {
185 delimiter: Delimiter,
187 stream: CellTokenStream,
189 leading_trivia: LeadingTrivia,
191 trailing_trivia: TrailingTrivia,
193}
194
195impl CellTokenGroup {
196 pub fn delimiter(&self) -> &Delimiter {
198 &self.delimiter
199 }
200
201 pub fn delim_kind(&self) -> DelimiterKind {
203 self.delimiter.kind
204 }
205
206 pub fn stream(&self) -> &CellTokenStream {
208 &self.stream
209 }
210
211 pub fn into_stream(self) -> CellTokenStream {
213 self.stream
214 }
215
216 fn from_augmented(group: TokenGroup) -> Self {
218 let (delimiter, stream, leading_trivia, trailing_trivia) = group.into_parts();
219 Self {
220 delimiter,
221 stream: CellTokenStream::from_augmented(stream),
222 leading_trivia,
223 trailing_trivia,
224 }
225 }
226
227 fn into_lexical(self) -> TokenGroup {
229 TokenGroup::from_parts(
230 self.delimiter,
231 self.stream.into_token_stream(),
232 self.leading_trivia,
233 self.trailing_trivia,
234 )
235 }
236
237 fn into_parser_group(self) -> TokenGroup {
239 TokenGroup::from_parts(
240 self.delimiter,
241 self.stream.into_parser_token_stream(),
242 self.leading_trivia,
243 self.trailing_trivia,
244 )
245 }
246}
247
248impl Spanned for CellTokenGroup {
249 fn try_span(&self) -> Option<Span> {
250 self.delimiter.try_span()
251 }
252}
253
254impl Terminal for CellTokenGroup {
255 fn leading_trivia(&self) -> &LeadingTrivia {
256 &self.leading_trivia
257 }
258
259 fn leading_trivia_mut(&mut self) -> &mut LeadingTrivia {
260 &mut self.leading_trivia
261 }
262
263 fn trailing_trivia(&self) -> &TrailingTrivia {
264 &self.trailing_trivia
265 }
266
267 fn trailing_trivia_mut(&mut self) -> &mut TrailingTrivia {
268 &mut self.trailing_trivia
269 }
270}
271
272#[derive(Debug, Clone, Default, PartialEq, Eq)]
273pub struct CellTokenStream(Arc<CellTokenStreamData>);
284
285impl CellTokenStream {
286 pub fn fork(&self) -> Self {
290 self.clone()
291 }
292
293 pub fn into_token_stream(self) -> TokenStream {
298 let CellTokenStreamData {
299 trees,
300 prefix,
301 suffix,
302 source,
303 } = self.into_data();
304 TokenStream::from_parts(TokenStreamParts {
305 trees: trees
306 .into_iter()
307 .filter_map(CellTokenTree::into_lexical)
308 .collect(),
309 prefix,
310 suffix,
311 source,
312 })
313 }
314
315 pub fn to_token_stream(&self) -> TokenStream {
319 self.clone().into_token_stream()
320 }
321
322 fn data(&self) -> &CellTokenStreamData {
324 &self.0
325 }
326
327 fn into_data(self) -> CellTokenStreamData {
329 Arc::try_unwrap(self.0).unwrap_or_else(|data| (*data).clone())
330 }
331
332 pub(crate) fn from_augmented(tokens: TokenStream) -> Self {
334 let TokenStreamParts {
335 trees,
336 prefix,
337 suffix,
338 source,
339 } = tokens.into_parts();
340 Self(Arc::new(CellTokenStreamData {
341 trees: trees
342 .into_iter()
343 .map(CellTokenTree::from_augmented)
344 .collect(),
345 prefix,
346 suffix,
347 source,
348 }))
349 }
350
351 pub(crate) fn source(&self) -> Option<Arc<Source>> {
353 self.data().source.clone().or_else(|| {
354 self.iter()
355 .find_map(Spanned::try_span)
356 .map(|span| Arc::clone(span.source()))
357 })
358 }
359
360 #[cfg(test)]
361 pub(crate) fn shares_storage(&self, other: &Self) -> bool {
362 Arc::ptr_eq(&self.0, &other.0)
363 }
364
365 pub(crate) fn into_parser_token_stream(self) -> TokenStream {
367 let CellTokenStreamData {
368 trees,
369 prefix,
370 suffix,
371 source,
372 } = self.into_data();
373 TokenStream::from_parts(TokenStreamParts {
374 trees: trees
375 .into_iter()
376 .map(CellTokenTree::into_parser_token)
377 .collect(),
378 prefix,
379 suffix,
380 source,
381 })
382 }
383
384 pub(crate) fn from_framed_cells(cells: impl IntoIterator<Item = CellTokenStream>) -> Self {
386 let mut tokens = TokenStream::new();
387 for cell in cells {
388 tokens.extend([cell.into_parser_token_stream()]);
389 }
390 Self::from_augmented(tokens)
391 }
392}
393
394impl Deref for CellTokenStream {
395 type Target = [CellTokenTree];
396
397 fn deref(&self) -> &Self::Target {
398 &self.data().trees
399 }
400}
401
402impl AsRef<[CellTokenTree]> for CellTokenStream {
403 fn as_ref(&self) -> &[CellTokenTree] {
404 self
405 }
406}
407
408impl Spanned for CellTokenStream {
409 fn try_span(&self) -> Option<Span> {
410 Span::join_all(
411 self.data()
412 .prefix
413 .try_span()
414 .into_iter()
415 .chain(self.iter().filter_map(Spanned::try_span))
416 .chain(self.data().suffix.try_span()),
417 )
418 }
419}
420
421impl Display for CellTokenStream {
422 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
423 self.to_token_stream().fmt(formatter)
424 }
425}
426
427impl IntoIterator for CellTokenStream {
428 type Item = CellTokenTree;
429 type IntoIter = IntoIter<CellTokenTree>;
430
431 fn into_iter(self) -> Self::IntoIter {
432 self.into_data().trees.into_iter()
433 }
434}
435
436impl<'syntax> IntoIterator for &'syntax CellTokenStream {
437 type Item = &'syntax CellTokenTree;
438 type IntoIter = Iter<'syntax, CellTokenTree>;
439
440 fn into_iter(self) -> Self::IntoIter {
441 self.iter()
442 }
443}
444
445#[derive(Debug, Clone, Default)]
446struct CellStreamData {
447 cells: Vec<CellTokenStream>,
448 source: Option<Arc<Source>>,
449}
450
451#[derive(Debug, Clone, Default)]
452pub struct CellStream(Arc<CellStreamData>);
464
465impl PartialEq for CellStream {
466 fn eq(&self, other: &Self) -> bool {
467 self.as_ref() == other.as_ref()
468 }
469}
470
471impl Eq for CellStream {}
472
473impl Deref for CellStream {
474 type Target = [CellTokenStream];
475
476 fn deref(&self) -> &Self::Target {
477 &self.data().cells
478 }
479}
480
481impl AsRef<[CellTokenStream]> for CellStream {
482 fn as_ref(&self) -> &[CellTokenStream] {
483 self
484 }
485}
486
487impl CellStream {
488 pub fn new(tokens: TokenStream) -> Result<Self, CellStreamError> {
501 let source = tokens.source();
502 let FramedCells { cells, incomplete } = frame_recovering(tokens);
503 match incomplete {
504 Some(tokens) => Err(CellStreamError {
505 span: end_span(&tokens),
506 }),
507 None => Ok(Self(Arc::new(CellStreamData { cells, source }))),
508 }
509 }
510
511 pub fn from_cells(cells: impl IntoIterator<Item = CellTokenStream>) -> Self {
517 Self::from_cells_with_source(cells, None)
518 }
519
520 pub(crate) fn from_cells_with_source(
522 cells: impl IntoIterator<Item = CellTokenStream>,
523 source: Option<Arc<Source>>,
524 ) -> Self {
525 Self(Arc::new(CellStreamData {
526 cells: cells.into_iter().collect(),
527 source,
528 }))
529 }
530
531 pub fn fork(&self) -> Self {
538 self.clone()
539 }
540
541 fn data(&self) -> &CellStreamData {
543 &self.0
544 }
545
546 fn data_mut(&mut self) -> &mut CellStreamData {
548 Arc::make_mut(&mut self.0)
549 }
550
551 fn into_data(self) -> CellStreamData {
553 Arc::try_unwrap(self.0).unwrap_or_else(|data| (*data).clone())
554 }
555
556 pub fn into_token_stream(self) -> TokenStream {
562 let source = self.complete_source();
563 let mut tokens = flatten_cells(self.into_data().cells);
564 if let Some(source) = source {
565 tokens.set_source(source);
566 }
567 tokens
568 }
569
570 pub fn to_token_stream(&self) -> TokenStream {
575 let mut tokens = flatten_cells(self.iter().cloned());
576 if let Some(source) = self.complete_source() {
577 tokens.set_source(source);
578 }
579 tokens
580 }
581
582 pub(crate) fn complete_source(&self) -> Option<Arc<Source>> {
584 let source = self.data().source.as_ref()?;
585 let mut cursor = 0;
586 for cell in self {
587 if !covers_stream(cell, source, &mut cursor) {
588 return None;
589 }
590 }
591 source.text()[cursor..]
592 .bytes()
593 .all(|byte| byte.is_ascii_whitespace())
594 .then(|| Arc::clone(source))
595 }
596
597 pub(crate) fn physical_eof(&self) -> Span {
599 if let Some(source) = self.complete_source() {
600 return Span::ranged(
601 Arc::clone(&source),
602 source.text().len()..source.text().len(),
603 );
604 }
605 self.last().map_or_else(|| Span::for_text(""), end_span)
606 }
607
608 #[cfg(feature = "tree-sitter")]
609 pub(crate) fn comment_ownership(&self) -> (Vec<CommentTrivia>, CommentTrivia) {
611 let mut cells = Vec::new();
612 let mut stream = CommentTrivia::default();
613 for tokens in self {
614 let mut tokens = tokens.clone().into_parser_token_stream();
615 if tokens.has_significant_tokens() {
616 cells.push(CommentTrivia::take_from_cell(&mut tokens));
617 } else {
618 stream.append(CommentTrivia::take_inner(&mut tokens));
619 }
620 }
621 (cells, stream)
622 }
623
624 pub(crate) fn from_source_file(source_file: &crate::SourceFile) -> Self {
626 let mut cells = source_file
627 .cells
628 .iter()
629 .map(Lex::to_token_stream)
630 .collect::<Vec<_>>();
631 if !source_file.comments.is_empty() {
632 if cells.is_empty() {
633 cells.push(TokenStream::new());
634 }
635 if let Some(cell) = cells.last_mut() {
636 source_file.comments.__apply_to(cell);
637 }
638 }
639 Self(Arc::new(CellStreamData {
640 cells: cells
641 .into_iter()
642 .map(CellTokenStream::from_augmented)
643 .collect(),
644 source: None,
645 }))
646 }
647}
648
649fn covers_stream(stream: &CellTokenStream, source: &Arc<Source>, cursor: &mut usize) -> bool {
651 for trivia in stream.data().prefix.as_slice() {
652 if !covers_span(trivia.span(), source, cursor) {
653 return false;
654 }
655 }
656 for token in stream.iter() {
657 for trivia in token.leading_trivia() {
658 if !covers_span(trivia.span(), source, cursor) {
659 return false;
660 }
661 }
662 let covered = match token {
663 CellTokenTree::Group(group) => {
664 covers_span(group.delimiter().opening_span(), source, cursor)
665 && covers_stream(group.stream(), source, cursor)
666 && group
667 .delimiter()
668 .closing_span()
669 .is_none_or(|span| covers_span(span, source, cursor))
670 }
671 _ => covers_span(token.span(), source, cursor),
672 };
673 if !covered {
674 return false;
675 }
676 for trivia in token.trailing_trivia() {
677 if !covers_span(trivia.span(), source, cursor) {
678 return false;
679 }
680 }
681 }
682 stream
683 .data()
684 .suffix
685 .as_slice()
686 .iter()
687 .all(|trivia| covers_span(trivia.span(), source, cursor))
688}
689
690fn covers_span(span: Span, source: &Arc<Source>, cursor: &mut usize) -> bool {
692 if !Arc::ptr_eq(span.source(), source) {
693 return false;
694 }
695 let (Some(start), Some(end)) = (span.start(), span.end()) else {
696 return false;
697 };
698 if start == end {
699 return start >= *cursor;
700 }
701 if start < *cursor
702 || !source.text()[*cursor..start]
703 .bytes()
704 .all(|byte| byte.is_ascii_whitespace())
705 {
706 return false;
707 }
708 *cursor = end;
709 true
710}
711
712impl Display for CellStream {
713 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
714 let mut previous: Option<Span> = None;
715 for (index, cell) in self.iter().enumerate() {
716 if index != 0 {
717 let next = cell_first_span(cell);
718 let mut recovered = false;
719 if let Some((left, right)) = previous.as_ref().zip(next.as_ref())
720 && left.shares_source(right)
721 && let (Some(end), Some(start)) = (left.end(), right.start())
722 && end <= start
723 {
724 let gap = &left.source().text()[end..start];
725 if !gap.is_empty() && gap.bytes().all(|byte| byte.is_ascii_whitespace()) {
726 formatter.write_str(gap)?;
727 recovered = true;
728 }
729 }
730 if !recovered {
731 formatter.write_str("\n")?;
732 }
733 }
734 cell.fmt(formatter)?;
735 previous = cell_last_span(cell);
736 }
737 Ok(())
738 }
739}
740
741fn cell_first_span(tokens: &CellTokenStream) -> Option<Span> {
743 tokens
744 .data()
745 .prefix
746 .as_slice()
747 .first()
748 .map(Spanned::span)
749 .or_else(|| {
750 tokens.iter().next().map(|token| {
751 token
752 .leading_trivia()
753 .first()
754 .map_or_else(|| token.span(), Spanned::span)
755 })
756 })
757 .or_else(|| tokens.data().suffix.as_slice().first().map(Spanned::span))
758}
759
760fn cell_last_span(tokens: &CellTokenStream) -> Option<Span> {
762 tokens
763 .data()
764 .suffix
765 .as_slice()
766 .last()
767 .map(Spanned::span)
768 .or_else(|| tokens.iter().next_back().map(token_end_span))
769 .or_else(|| tokens.data().prefix.as_slice().last().map(Spanned::span))
770}
771
772impl IntoIterator for CellStream {
773 type Item = CellTokenStream;
774 type IntoIter = IntoIter<CellTokenStream>;
775
776 fn into_iter(self) -> Self::IntoIter {
777 self.into_data().cells.into_iter()
778 }
779}
780
781impl<'syntax> IntoIterator for &'syntax CellStream {
782 type Item = &'syntax CellTokenStream;
783 type IntoIter = Iter<'syntax, CellTokenStream>;
784
785 fn into_iter(self) -> Self::IntoIter {
786 self.iter()
787 }
788}
789
790impl FromIterator<CellTokenStream> for CellStream {
791 fn from_iter<T: IntoIterator<Item = CellTokenStream>>(iter: T) -> Self {
792 Self::from_cells(iter)
793 }
794}
795
796fn flatten_cells(cells: impl IntoIterator<Item = CellTokenStream>) -> TokenStream {
798 let mut output = TokenStream::new();
799 for cell in cells {
800 output.extend([cell.into_token_stream()]);
801 }
802 output
803}
804
805#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
806pub struct CellStreamError {
812 span: Span,
814}
815
816impl Display for CellStreamError {
817 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
818 formatter.write_str("input ends inside an incomplete cell")
819 }
820}
821
822impl Error for CellStreamError {}
823
824pub trait Tokenize {
850 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError>;
857
858 fn to_cell_stream(&self) -> Result<CellStream, CellStreamError> {
867 let mut output = CellStream::default();
868 self.tokenize(&mut output)?;
869 Ok(output)
870 }
871}
872
873impl Tokenize for TokenStream {
874 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError> {
875 let tokenized = CellStream::new(self.clone())?.into_data();
876 let output = output.data_mut();
877 if output.cells.is_empty() {
878 output.source = tokenized.source;
879 } else {
880 output.source = None;
881 }
882 output.cells.extend(tokenized.cells);
883 Ok(())
884 }
885}
886
887impl Tokenize for crate::SourceFile {
888 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError> {
889 let tokenized = CellStream::from_source_file(self).into_data();
890 let output = output.data_mut();
891 output.cells.extend(tokenized.cells);
892 output.source = None;
893 Ok(())
894 }
895}
896
897impl Tokenize for crate::ParsedFile {
898 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError> {
899 self.cst().tokenize(output)
900 }
901}
902
903impl<T: Tokenize + ?Sized> Tokenize for &T {
904 fn tokenize(&self, output: &mut CellStream) -> Result<(), CellStreamError> {
905 (*self).tokenize(output)
906 }
907}
908
909pub(crate) struct FramedCells {
915 pub(crate) cells: Vec<CellTokenStream>,
917 pub(crate) incomplete: Option<CellTokenStream>,
919}
920
921pub(crate) fn frame_recovering(tokens: TokenStream) -> FramedCells {
935 let mut tokens = tokens;
936 let prefix_trivia = tokens.take_prefix_trivia();
939 let suffix_trivia = tokens.take_suffix_trivia();
940 let mut cells = Vec::new();
941 let mut current = TokenStream::new();
942 current.extend(prefix_trivia.into_vec());
943 let mut pending_boundary = false;
944 let mut quote_next = false;
945
946 for token in tokens {
947 if pending_boundary {
950 cells.push(insert_adjacency(take(&mut current)));
951 pending_boundary = false;
952 quote_next = false;
953 } else if current
954 .last()
955 .is_some_and(|left| tokens_cross_line_break(left, &token))
956 && newline_ends_cell(¤t)
957 {
958 cells.push(insert_adjacency(take(&mut current)));
959 quote_next = false;
960 }
961
962 let quoted = take(&mut quote_next);
963 let quotes_next = !quoted
964 && matches!(&token, TokenTree::Ident(identifier)
965 if is_quote_specifier(canonical_word_spelling(identifier.text())));
966 let semicolon = !quoted && token.spelling() == Some(";");
967
968 current.extend([token]);
969 if semicolon {
970 pending_boundary = true;
971 }
972 if quotes_next {
973 quote_next = true;
974 }
975 }
976
977 current.extend(suffix_trivia.into_vec());
978
979 if pending_boundary {
982 cells.push(insert_adjacency(current));
983 return FramedCells {
984 cells,
985 incomplete: None,
986 };
987 }
988
989 if !has_syntax(¤t) {
992 if current.has_trivia() {
993 cells.push(CellTokenStream::from_augmented(current));
994 }
995 return FramedCells {
996 cells,
997 incomplete: None,
998 };
999 }
1000
1001 if !ends_in_incomplete_group(¤t) && newline_ends_cell(¤t) {
1004 cells.push(insert_adjacency(current));
1005 FramedCells {
1006 cells,
1007 incomplete: None,
1008 }
1009 } else {
1010 FramedCells {
1011 cells,
1012 incomplete: Some(insert_adjacency(current)),
1013 }
1014 }
1015}
1016
1017pub(crate) fn end_span(tokens: &CellTokenStream) -> Span {
1019 let ends_with_semicolon = ends_with_cell_semicolon(tokens);
1020 let span = tokens
1021 .iter()
1022 .next_back()
1023 .map(token_end_span)
1024 .or_else(|| tokens.data().suffix.as_slice().last().map(Spanned::span))
1025 .or_else(|| tokens.data().prefix.as_slice().last().map(Spanned::span));
1026 let Some(span) = span else {
1027 return Span::for_text("");
1028 };
1029 let Some(end) = span.end() else {
1030 return Span::unlocated(Arc::clone(span.source()));
1031 };
1032 if !ends_with_semicolon && let Some(newline) = span.source().text()[end..].find('\n') {
1033 return span.at(end + newline + 1);
1034 }
1035 span.at(end)
1036}
1037
1038fn token_end_span(token: &CellTokenTree) -> Span {
1040 if let Some(trivia) = token.trailing_trivia().last() {
1041 return trivia.span();
1042 }
1043 if let CellTokenTree::Group(group) = token
1044 && !group.delimiter().is_closed()
1045 && let Some(inner) = group.stream().iter().next_back()
1046 {
1047 return token_end_span(inner);
1048 }
1049 token.span()
1050}
1051
1052pub(crate) fn ends_with_cell_semicolon(tokens: &CellTokenStream) -> bool {
1054 let mut quote_next = false;
1055 let mut final_semicolon = false;
1056 for token in tokens.iter() {
1057 let quoted = take(&mut quote_next);
1058 final_semicolon = !quoted && token.spelling() == Some(";");
1059 quote_next = !quoted
1060 && matches!(token, CellTokenTree::Ident(identifier)
1061 if is_quote_specifier(canonical_word_spelling(identifier.text())));
1062 }
1063 final_semicolon
1064}
1065
1066fn has_syntax(stream: &TokenStream) -> bool {
1068 !stream.is_empty()
1069}
1070
1071fn ends_in_incomplete_group(stream: &TokenStream) -> bool {
1073 matches!(stream.iter().next_back(), Some(TokenTree::Group(group)) if !group.delimiter().is_closed())
1074}
1075
1076fn insert_adjacency(mut tokens: TokenStream) -> CellTokenStream {
1078 let prefix = tokens.take_prefix_trivia();
1079 let suffix = tokens.take_suffix_trivia();
1080 let mut output = TokenStream::new();
1081 output.extend(prefix.into_vec());
1082 let mut left_can_end = false;
1083 let mut quote_next = false;
1084
1085 for mut token in tokens {
1086 if let TokenTree::Group(group) = &mut token {
1087 let contents = take(group.stream_mut());
1088 *group.stream_mut() = insert_adjacency(contents).into_parser_token_stream();
1089 }
1090
1091 let quoted = take(&mut quote_next);
1092 let crossed_newline = output
1093 .last()
1094 .is_some_and(|left| tokens_cross_line_break(left, &token));
1095 if left_can_end && !quoted && !crossed_newline && can_begin_implicit_operand(&token) {
1096 let span = token.expect_span().subspan(0, 0);
1097 output.extend([TokenTree::Punct(Punct::from_span(span))]);
1098 }
1099
1100 let quotes_next = !quoted
1101 && matches!(&token, TokenTree::Ident(identifier)
1102 if is_quote_specifier(canonical_word_spelling(identifier.text())));
1103 left_can_end = quoted || can_end_operand(&token);
1104 quote_next = quotes_next;
1105 output.extend([token]);
1106 }
1107 for trivia in suffix.into_vec() {
1108 output.push_leading_trivia(trivia);
1109 }
1110 CellTokenStream::from_augmented(output)
1111}
1112
1113fn tokens_cross_line_break(left: &TokenTree, right: &TokenTree) -> bool {
1115 let left = left.expect_span();
1116 let right = right.expect_span();
1117 if !left.shares_source(&right) {
1118 return false;
1119 }
1120 let (Some(end), Some(start)) = (left.end(), right.start()) else {
1121 return false;
1122 };
1123 end <= start && left.source().text()[end..start].contains('\n')
1124}
1125
1126fn token_parse_rule(token: &TokenTree) -> Option<TokenParseRule> {
1128 let spelling = token.spelling().map(canonical_word_spelling)?;
1129 TOKEN_PARSE_RULES
1130 .binary_search_by_key(&spelling, |(declared, _)| *declared)
1131 .ok()
1132 .map(|index| TOKEN_PARSE_RULES[index].1)
1133}
1134
1135fn can_begin_implicit_operand(token: &TokenTree) -> bool {
1137 match token_parse_rule(token) {
1138 Some(TokenParseRule::Prefix(_, _) | TokenParseRule::Unary(_, _)) => true,
1139 Some(_) => false,
1140 None => matches!(
1141 token,
1142 TokenTree::Ident(_) | TokenTree::Literal(_) | TokenTree::Group(_)
1143 ),
1144 }
1145}
1146
1147fn can_end_operand(token: &TokenTree) -> bool {
1149 match token_parse_rule(token) {
1150 Some(TokenParseRule::Postfix(_)) => true,
1151 Some(_) => false,
1152 None => matches!(
1153 token,
1154 TokenTree::Ident(_) | TokenTree::Literal(_) | TokenTree::Group(_)
1155 ),
1156 }
1157}
1158
1159#[cfg(test)]
1160mod tests {
1161 use super::{Arc, CellStream};
1162 use crate::{CellTokenTree, TokenTree, Tokenize, TriviaKind, lex_str};
1163
1164 fn count_cell_adjacency(tokens: &[CellTokenTree]) -> usize {
1165 tokens
1166 .iter()
1167 .map(|token| match token {
1168 CellTokenTree::Group(group) => count_cell_adjacency(group.stream()),
1169 CellTokenTree::Adj(_) => 1,
1170 _ => 0,
1171 })
1172 .sum()
1173 }
1174
1175 fn count_raw_adjacency(tokens: &[TokenTree]) -> usize {
1176 tokens
1177 .iter()
1178 .map(|token| match token {
1179 TokenTree::Group(group) => count_raw_adjacency(group.stream()),
1180 TokenTree::Punct(punctuation) if punctuation.text().is_empty() => 1,
1181 _ => 0,
1182 })
1183 .sum()
1184 }
1185
1186 #[test]
1187 fn cells_are_structural_partitions() {
1188 let cells = CellStream::new(lex_str("f \t-- note\n x").unwrap()).unwrap();
1189 assert_eq!(cells.len(), 2);
1190 assert_eq!(cells.to_string(), "f \t-- note\n x");
1191 }
1192
1193 #[test]
1194 fn same_line_application_gets_one_empty_punctuation() {
1195 let cells = lex_str("f x").unwrap().to_cell_stream().unwrap();
1196 assert_eq!(
1197 cells
1198 .iter()
1199 .flat_map(|cell| cell.iter())
1200 .filter(|token| matches!(token, CellTokenTree::Adj(_)))
1201 .count(),
1202 1,
1203 );
1204 }
1205
1206 #[test]
1207 fn flattening_a_framed_cell_restores_lexical_tokens() {
1208 let raw = lex_str("f (g x)").unwrap();
1209 assert_eq!(count_raw_adjacency(&raw), 0);
1210
1211 let cells = raw.to_cell_stream().unwrap();
1212 assert_eq!(count_cell_adjacency(&cells[0]), 2);
1213
1214 let raw = cells.into_token_stream();
1215 assert_eq!(count_raw_adjacency(&raw), 0);
1216 assert_eq!(raw.to_string(), "f (g x)");
1217 }
1218
1219 #[test]
1220 fn line_comment_blocks_begin_the_cell_on_their_right() {
1221 let cells = CellStream::new(lex_str("x\n-- first\n-- second\ny").unwrap()).unwrap();
1222 assert_eq!(cells.len(), 2);
1223 let comments = cells[1].iter().next().unwrap().leading_trivia();
1224 assert_eq!(comments.len(), 1);
1225 assert_eq!(comments[0].kind(), TriviaKind::LineComment);
1226 assert_eq!(comments[0].text(), "-- first\n-- second");
1227 }
1228
1229 #[test]
1230 fn a_blank_line_separates_outer_comment_blocks() {
1231 let cells = CellStream::new(lex_str("-- first\n\n-- second\ny").unwrap()).unwrap();
1232 let comments = cells[0].iter().next().unwrap().leading_trivia();
1233
1234 assert_eq!(comments.len(), 2);
1235 assert_eq!(comments[0].text(), "-- first");
1236 assert_eq!(comments[1].text(), "-- second");
1237 }
1238
1239 #[test]
1240 fn line_comments_do_not_split_an_incomplete_cell() {
1241 let cells = CellStream::new(lex_str("x + -- reason\ny").unwrap()).unwrap();
1242 assert_eq!(cells.len(), 1);
1243 assert!(cells[0].iter().any(|token| {
1244 token
1245 .trailing_trivia()
1246 .iter()
1247 .any(|trivia| trivia.kind() == TriviaKind::LineComment)
1248 }));
1249 }
1250
1251 #[test]
1252 fn fork_copies_only_the_modified_cell_path() {
1253 let original = CellStream::new(lex_str("left; right").unwrap()).unwrap();
1254 let mut fork = original.fork();
1255
1256 assert!(Arc::ptr_eq(&original.0, &fork.0));
1257
1258 fork.data_mut().cells.pop();
1259
1260 assert!(!Arc::ptr_eq(&original.0, &fork.0));
1261 assert_eq!(original.to_string(), "left; right");
1262 assert_eq!(fork.to_string(), "left;");
1263 assert!(original[0].shares_storage(&fork[0]));
1264 }
1265}