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