1use std::error::Error;
9use std::fmt::{Display, Formatter};
10
11use crate::cell_stream::{end_span, ends_with_cell_semicolon, frame_recovering};
12use crate::lexer::canonical_word_spelling;
13use crate::nodes::*;
14use crate::parse::{Lookahead, SignificantToken};
15use crate::{
16 CellStream, CellStreamError, CellTokenStream, CommentTrivia, Delimited, DelimiterKind,
17 DelimiterToken, DelimiterValue, LeadingTrivia, LexError, LexErrorKind, LiteralKind, Parse,
18 ParseStream, Parser, Punctuated, Recovered, Span, Spanned, Terminal, Token, TokenParseError,
19 TokenStream, TokenTree, Tokenize, TrailingTrivia, Trivia, lex_str, lex_str_recovering,
20};
21
22macro_rules! is_token {
24 ($token:expr, $($pattern:tt)*) => {
25 <Token![$($pattern)*] as Token>::matches_token_tree($token)
26 };
27}
28
29macro_rules! unexpected {
31 ($token:expr, $expected:expr) => {{
32 let token = $token;
33 NativeParseError::Unexpected {
34 span: token.expect_span(),
35 found: token.description(),
36 expected: $expected,
37 }
38 }};
39}
40
41const PREC_CLOSER: u8 = 6;
43const PREC_COMMA: u8 = 10;
45const PREC_CONTROL: u8 = 12;
47const PREC_LOOP_CLAUSE: u8 = 16;
49const PREC_COLLECTION: u8 = 56;
51const PREC_APPLICATION_RIGHT: u8 = 61;
53const PREC_APPLICATION: u8 = 62;
55
56#[derive(Debug)]
58pub struct NativeParser;
59
60impl Parser for NativeParser {
61 type Error = NativeParseError;
62
63 fn parse_cells(&mut self, cells: CellStream) -> Result<SourceFile, Self::Error> {
64 parse_cell_stream(cells)
65 }
66}
67
68pub fn parse_native(source: &str) -> Result<SourceFile, NativeParseError> {
75 let tokens = lex_str(source).map_err(NativeParseError::Lex)?;
76 let cells = tokenize_for_native_parser(tokens)?;
77 NativeParser.parse_cells(cells)
78}
79
80pub fn parse_native_recovering(
91 source: &str,
92) -> Result<Recovered<SourceFile, LexError>, NativeParseError> {
93 let recovered = lex_str_recovering(source).map_err(NativeParseError::Lex)?;
94 let (tokens, diagnostics) = recovered.into_parts();
95 let source = tokens.source();
96 let framed = frame_recovering(tokens);
97 let cells = CellStream::from_cells_with_source(
98 framed.cells.into_iter().chain(framed.incomplete),
99 source,
100 );
101 let syntax = NativeParser.parse_cells(cells)?;
102 Ok(Recovered::new(syntax, diagnostics))
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
107pub enum NativeCellState {
108 Empty,
110 Complete,
112 Incomplete,
114 Invalid,
116}
117
118#[derive(Debug)]
120pub struct CompletedNativeCell {
121 source: Span,
123 syntax: crate::nodes::Cell,
125}
126
127impl CompletedNativeCell {
128 pub fn source(&self) -> &str {
134 self.source
135 .text()
136 .expect("completed cell source spans must resolve to text")
137 }
138
139 pub fn syntax(&self) -> &crate::nodes::Cell {
141 &self.syntax
142 }
143
144 pub fn into_parts(self) -> (Span, crate::nodes::Cell) {
146 (self.source, self.syntax)
147 }
148}
149
150#[derive(Debug)]
175pub struct NativeCellParser {
176 active_source: String,
178 active_tokens: TokenStream,
180 active_syntax: Option<crate::nodes::Cell>,
182 completed: Vec<CompletedNativeCell>,
184 lexer_diagnostics: Vec<LexError>,
186 parse_error: Option<NativeParseError>,
188 state: NativeCellState,
190}
191
192impl Default for NativeCellParser {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198impl NativeCellParser {
199 pub fn new() -> Self {
201 Self {
202 active_source: String::new(),
203 active_tokens: TokenStream::new(),
204 active_syntax: None,
205 completed: Vec::new(),
206 lexer_diagnostics: Vec::new(),
207 parse_error: None,
208 state: NativeCellState::Empty,
209 }
210 }
211
212 pub fn push_line(&mut self, line: &str) -> NativeCellState {
219 self.active_source.push_str(line);
220 if !line.ends_with('\n') {
221 self.active_source.push('\n');
222 }
223 self.refresh()
224 }
225
226 pub fn state(&self) -> NativeCellState {
228 self.state
229 }
230
231 pub fn active_source(&self) -> &str {
233 &self.active_source
234 }
235
236 pub fn active_tokens(&self) -> &TokenStream {
238 &self.active_tokens
239 }
240
241 pub fn active_syntax(&self) -> Option<&crate::nodes::Cell> {
243 self.active_syntax.as_ref()
244 }
245
246 pub fn lexer_diagnostics(&self) -> &[LexError] {
248 &self.lexer_diagnostics
249 }
250
251 pub fn parse_error(&self) -> Option<&NativeParseError> {
253 self.parse_error.as_ref()
254 }
255
256 pub fn completed(&self) -> &[CompletedNativeCell] {
258 &self.completed
259 }
260
261 pub fn take_completed(&mut self) -> Vec<CompletedNativeCell> {
263 let completed = std::mem::take(&mut self.completed);
264 if self.state == NativeCellState::Complete {
265 self.state = NativeCellState::Empty;
266 }
267 completed
268 }
269
270 pub fn reset_active(&mut self) {
272 self.active_source.clear();
273 self.active_tokens = TokenStream::new();
274 self.active_syntax = None;
275 self.lexer_diagnostics.clear();
276 self.parse_error = None;
277 self.state = if self.completed.is_empty() {
278 NativeCellState::Empty
279 } else {
280 NativeCellState::Complete
281 };
282 }
283
284 fn refresh(&mut self) -> NativeCellState {
286 self.active_tokens = TokenStream::new();
287 self.active_syntax = None;
288 self.lexer_diagnostics.clear();
289 self.parse_error = None;
290
291 loop {
292 let recovered = match lex_str_recovering(&self.active_source) {
293 Ok(recovered) => recovered,
294 Err(error) => {
295 self.state = if incomplete_lex_error(error.kind()) {
296 NativeCellState::Incomplete
297 } else {
298 NativeCellState::Invalid
299 };
300 self.lexer_diagnostics.push(error);
301 return self.state;
302 }
303 };
304 let (tokens, diagnostics) = recovered.into_parts();
305 let framed = frame_recovering(tokens.clone());
306 let has_incomplete = framed.incomplete.is_some();
307 let mut cells = framed.cells.into_iter().map(|cell| (cell, true));
308 let first = cells
309 .next()
310 .or_else(|| framed.incomplete.map(|cell| (cell, false)));
311 let Some((cell, cell_complete)) = first else {
312 self.active_tokens = tokens;
313 self.lexer_diagnostics = diagnostics;
314 self.state = if self.completed.is_empty() {
315 NativeCellState::Empty
316 } else {
317 NativeCellState::Complete
318 };
319 return self.state;
320 };
321
322 let has_following_cell = cells.next().is_some() || has_incomplete;
323 let ended_by_semicolon = ends_with_cell_semicolon(&cell);
324 let boundary = end_span(&cell);
325 let end = boundary.end().unwrap_or(self.active_source.len());
326 let source = Span::ranged(std::sync::Arc::clone(boundary.source()), 0..end);
327
328 match parse_raw_cell(cell) {
329 Ok(Some(syntax)) if cell_complete && has_following_cell => {
330 self.completed.push(CompletedNativeCell { source, syntax });
331 self.active_source.replace_range(..end, "");
332 }
333 Ok(Some(syntax)) if cell_complete && diagnostics.is_empty() => {
334 self.completed.push(CompletedNativeCell { source, syntax });
335 self.active_source.clear();
336 self.active_tokens = TokenStream::new();
337 self.state = NativeCellState::Complete;
338 return self.state;
339 }
340 Ok(Some(syntax)) => {
341 self.active_tokens = tokens;
342 self.active_syntax = Some(syntax);
343 self.lexer_diagnostics = diagnostics;
344 self.state = NativeCellState::Incomplete;
345 return self.state;
346 }
347 Ok(None) => {
348 self.active_tokens = tokens;
349 self.lexer_diagnostics = diagnostics;
350 self.state = if self.completed.is_empty() {
351 NativeCellState::Empty
352 } else {
353 NativeCellState::Complete
354 };
355 return self.state;
356 }
357 Err(error) => {
358 let can_append_to_cell =
359 !cell_complete || (!has_following_cell && !ended_by_semicolon);
360 self.state = if can_append_to_cell && incomplete_parse_error(&error) {
361 NativeCellState::Incomplete
362 } else {
363 NativeCellState::Invalid
364 };
365 self.active_tokens = tokens;
366 self.lexer_diagnostics = diagnostics;
367 self.parse_error = Some(error);
368 return self.state;
369 }
370 }
371 }
372 }
373}
374
375pub(crate) fn incomplete_lex_error(kind: LexErrorKind) -> bool {
377 matches!(
378 kind,
379 LexErrorKind::UnterminatedGroup
380 | LexErrorKind::UnterminatedString
381 | LexErrorKind::UnterminatedRawString
382 | LexErrorKind::UnterminatedBlockComment
383 )
384}
385
386pub(crate) fn incomplete_parse_error(error: &NativeParseError) -> bool {
388 match error {
389 NativeParseError::MissingOperand { .. } => true,
390 NativeParseError::Unexpected { found, .. } => found == "end of input",
391 NativeParseError::Lex(error) => incomplete_lex_error(error.kind()),
392 NativeParseError::Tokenize(_) => true,
393 NativeParseError::NewlineInApplication { .. }
394 | NativeParseError::InvalidAssignmentTarget { .. }
395 | NativeParseError::InvalidLambdaArguments { .. }
396 | NativeParseError::Unsupported { .. } => false,
397 }
398}
399
400#[derive(Debug, Spanned)]
401pub enum NativeParseError {
403 Lex(LexError),
405 Tokenize(CellStreamError),
407 Unexpected {
409 found: String,
411 expected: &'static str,
413 span: Span,
415 },
416 MissingOperand {
418 operator: String,
420 span: Span,
422 },
423 NewlineInApplication {
425 span: Span,
427 },
428 InvalidAssignmentTarget {
430 span: Span,
432 },
433 InvalidLambdaArguments {
435 span: Span,
437 },
438 Unsupported {
440 syntax: String,
442 span: Span,
444 },
445}
446
447impl NativeParseError {
448 fn unexpected_end(expected: &'static str, span: Span) -> Self {
450 Self::Unexpected {
451 found: "end of input".into(),
452 expected,
453 span,
454 }
455 }
456
457 fn missing_operand_for(self, operator: &TokenTree) -> Self {
459 if matches!(self, Self::MissingOperand { .. }) {
460 Self::MissingOperand {
461 operator: operator.description(),
462 span: operator.expect_span(),
463 }
464 } else {
465 self
466 }
467 }
468}
469
470impl Display for NativeParseError {
471 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
472 match self {
473 Self::Lex(error) => error.fmt(formatter),
474 Self::Tokenize(error) => error.fmt(formatter),
475 Self::Unexpected {
476 found, expected, ..
477 } => write!(formatter, "expected {expected}, found `{found}`"),
478 Self::MissingOperand { operator, .. } => {
479 write!(
480 formatter,
481 "expected an operand after `{operator}`, found end of input"
482 )
483 }
484 Self::NewlineInApplication { .. } => {
485 formatter.write_str("implicit application cannot cross a line break")
486 }
487 Self::InvalidAssignmentTarget { .. } => {
488 formatter.write_str("invalid assignment target")
489 }
490 Self::InvalidLambdaArguments { .. } => {
491 formatter.write_str("invalid lambda argument list")
492 }
493 Self::Unsupported { syntax, .. } => {
494 write!(
495 formatter,
496 "native parsing of `{syntax}` is not implemented yet"
497 )
498 }
499 }
500 }
501}
502
503impl Error for NativeParseError {
504 fn source(&self) -> Option<&(dyn Error + 'static)> {
505 match self {
506 Self::Lex(error) => Some(error),
507 Self::Tokenize(error) => Some(error),
508 _ => None,
509 }
510 }
511}
512
513#[derive(Debug, Clone, Copy)]
514enum UnaryAction {
520 Atom,
522 Prefix,
524 Statement,
526 Control,
528 Debug,
530 Delimiter,
532 Quote,
534 Error,
536}
537
538#[derive(Debug, Clone, Copy)]
539struct ParseInfo {
541 precedence: u8,
543 binary_strength: Option<u8>,
545 unary_strength: Option<u8>,
547 unary: UnaryAction,
549 postfix: bool,
551}
552
553impl From<TokenParseRule> for ParseInfo {
554 fn from(rule: TokenParseRule) -> Self {
555 match rule {
556 TokenParseRule::Precedence(precedence) => Self::stop(precedence),
557 TokenParseRule::Postfix(precedence) => Self::postfix(precedence),
558 TokenParseRule::Binary(precedence, strength) => Self::binary(precedence, strength),
559 TokenParseRule::Prefix(precedence, strength) => {
560 Self::unary(precedence, UnaryAction::Prefix, strength)
561 }
562 TokenParseRule::PrefixBinary(precedence, binary, unary) => {
563 Self::prefix_binary(precedence, binary, unary)
564 }
565 TokenParseRule::Unary(precedence, strength) => {
566 Self::unary(precedence, UnaryAction::Error, strength)
567 }
568 }
569 }
570}
571
572impl ParseInfo {
573 const fn atom(precedence: u8) -> Self {
575 Self {
576 precedence,
577 binary_strength: None,
578 unary_strength: None,
579 unary: UnaryAction::Atom,
580 postfix: false,
581 }
582 }
583
584 const fn binary(precedence: u8, strength: u8) -> Self {
586 Self {
587 precedence,
588 binary_strength: Some(strength),
589 unary_strength: None,
590 unary: UnaryAction::Error,
591 postfix: false,
592 }
593 }
594
595 const fn prefix_binary(precedence: u8, binary_strength: u8, unary_strength: u8) -> Self {
597 Self {
598 precedence,
599 binary_strength: Some(binary_strength),
600 unary_strength: Some(unary_strength),
601 unary: UnaryAction::Prefix,
602 postfix: false,
603 }
604 }
605
606 const fn unary(precedence: u8, unary: UnaryAction, strength: u8) -> Self {
610 Self {
611 precedence,
612 binary_strength: None,
613 unary_strength: Some(strength),
614 unary,
615 postfix: false,
616 }
617 }
618
619 const fn postfix(precedence: u8) -> Self {
621 Self {
622 precedence,
623 binary_strength: None,
624 unary_strength: None,
625 unary: UnaryAction::Error,
626 postfix: true,
627 }
628 }
629
630 const fn delimiter(precedence: u8) -> Self {
632 Self {
633 precedence,
634 binary_strength: None,
635 unary_strength: Some(PREC_CLOSER),
636 unary: UnaryAction::Delimiter,
637 postfix: false,
638 }
639 }
640
641 const fn stop(precedence: u8) -> Self {
643 Self {
644 precedence,
645 binary_strength: None,
646 unary_strength: None,
647 unary: UnaryAction::Error,
648 postfix: false,
649 }
650 }
651}
652
653struct Engine {
655 input: ParseStream,
657}
658
659struct Components<T> {
661 first: T,
663 rest: Vec<(Token![,], T)>,
665}
666
667impl<T> Components<T> {
668 fn from_punctuated(values: Punctuated<T>) -> Self {
670 let (pair, rest) = values.into_parts();
671 let (first, punctuation, second) = pair.into_parts();
672 let mut pairs = Vec::with_capacity(rest.len() + 1);
673 pairs.push((punctuation, second));
674 pairs.extend(rest);
675 Self { first, rest: pairs }
676 }
677
678 fn is_punctuated(&self) -> bool {
680 !self.rest.is_empty()
681 }
682
683 fn into_punctuated(self) -> Result<Punctuated<T>, T> {
685 let mut rest = self.rest.into_iter();
686 let Some((punctuation, second)) = rest.next() else {
687 return Err(self.first);
688 };
689 let mut values = Punctuated::new(self.first, punctuation, second);
690 for (punctuation, value) in rest {
691 values.push(punctuation, value);
692 }
693 Ok(values)
694 }
695
696 fn map<U>(self, mut map: impl FnMut(T) -> Option<U>) -> Option<Components<U>> {
698 Some(Components {
699 first: map(self.first)?,
700 rest: self
701 .rest
702 .into_iter()
703 .map(|(punctuation, value)| Some((punctuation, map(value)?)))
704 .collect::<Option<Vec<_>>>()?,
705 })
706 }
707}
708
709impl Engine {
710 fn new(tokens: TokenStream) -> Self {
712 Self {
713 input: ParseStream::new(tokens),
714 }
715 }
716
717 fn parse_cell(
719 mut self,
720 semicolon: Option<Token![;]>,
721 eoc_span: Span,
722 ) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
723 self.skip_trivia();
724 if matches!(self.peek(), Lookahead::End(_)) {
725 return match semicolon {
726 None => Ok(None),
727 Some(semicolon) => Err(NativeParseError::Unexpected {
728 found: ";".into(),
729 expected: "a statement before `;`",
730 span: semicolon.expect_span(),
731 }),
732 };
733 }
734
735 let components = self.parse_components()?;
736
737 if let Lookahead::Token(token) = self.peek() {
738 return Err(unexpected!(token.token, "the end of the cell"));
739 }
740
741 let eoc = EOC::new("", eoc_span);
742 Ok(Some(crate::nodes::Cell::new(
743 self.packed_content(components)?,
744 semicolon,
745 eoc,
746 )))
747 }
748
749 fn parse_components(&mut self) -> Result<Components<Component>, NativeParseError> {
751 let first = if self.at_punctuation(",") {
752 Component::Empty(Empty::new("", empty_span_at(&self.peek().expect_span())))
753 } else {
754 self.parse_required(PREC_COMMA)?.into()
755 };
756 let mut rest = Vec::new();
757
758 while let Some(comma) = self.take_punctuation(",") {
759 let next = if self.at_end() || self.at_punctuation(";") || self.at_punctuation(",") {
760 Component::Empty(Empty::new("", empty_span_at(&self.peek().expect_span())))
761 } else {
762 self.parse_required(PREC_COMMA)?.into()
763 };
764 rest.push((typed_token(comma), next));
765 }
766
767 Ok(Components { first, rest })
768 }
769
770 fn parse_optional_components(
772 &mut self,
773 ) -> Result<Option<Components<Component>>, NativeParseError> {
774 if self.at_end() || self.at_punctuation(";") {
775 Ok(None)
776 } else {
777 self.parse_components().map(Some)
778 }
779 }
780
781 fn parse_required(&mut self, level: u8) -> Result<Expr, NativeParseError> {
783 let token = match self.consume() {
784 Lookahead::Token(token) => token,
785 Lookahead::End(span) => {
786 return Err(NativeParseError::MissingOperand {
787 operator: "end of input".into(),
788 span,
789 });
790 }
791 };
792 self.parse_consumed(token, level)
793 }
794
795 fn parse_nullable(&mut self, level: u8) -> Result<Option<Expr>, NativeParseError> {
797 let lookahead = self.peek();
798 let Lookahead::Token(token) = lookahead else {
799 return Ok(None);
800 };
801 if parse_info(&token.token).precedence <= level {
802 return Ok(None);
803 }
804 let Lookahead::Token(token) = self.consume() else {
805 unreachable!("the token just peeked is consumable")
806 };
807 self.parse_consumed(token, level).map(Some)
808 }
809
810 fn parse_consumed(
812 &mut self,
813 token: SignificantToken,
814 level: u8,
815 ) -> Result<Expr, NativeParseError> {
816 let info = parse_info(&token.token);
817 let result = match info.unary {
818 UnaryAction::Atom => lower_atom(token)?,
819 UnaryAction::Prefix => {
820 let strength = info.unary_strength.expect("prefix operators have U");
821 let operand = self.parse_required(level.max(strength))?;
822 let span = token.token.expect_span();
823 let spelling = token.token.description();
824 let operator =
825 PrefixOperator::from_token_tree_with_trivia(token.token, token.trailing_trivia)
826 .ok_or({
827 NativeParseError::Unsupported {
828 syntax: spelling,
829 span,
830 }
831 })?;
832 Expr!(Op::Prefix {
833 operator,
834 operand: Box::new(operand),
835 })
836 }
837 UnaryAction::Statement => {
838 let strength = info
839 .unary_strength
840 .expect("prefix statements have a unary binding strength");
841 let operand = if is_token!(&token.token, break)
842 || is_token!(&token.token, continue)
843 || is_token!(&token.token, return)
844 {
845 self.parse_nullable(level.max(strength))?
846 } else {
847 self.parse_required(level.max(strength))
848 .map_err(|error| error.missing_operand_for(&token.token))?
849 .into()
850 };
851 lower_prefix_statement(token, operand)
852 }
853 UnaryAction::Control => {
854 if is_token!(&token.token, if) {
855 self.parse_if_statement(token)?
856 } else if is_token!(&token.token, for) {
857 self.parse_for_loop(token)?
858 } else if is_token!(&token.token, while) {
859 self.parse_while_loop(token)?
860 } else if is_token!(&token.token, try) {
861 self.parse_try_statement(token)?
862 } else if is_token!(&token.token, new) {
863 self.parse_new_statement(token)?
864 } else {
865 unreachable!("control actions are assigned only to control keywords")
866 }
867 }
868 UnaryAction::Debug => self.parse_debug_clause(token)?,
869 UnaryAction::Delimiter => parse_delimited(token)?,
870 UnaryAction::Quote => {
871 let operator = token.token.description();
872 let quoted = match self.consume() {
873 Lookahead::Token(quoted) => quoted,
874 Lookahead::End(span) => {
875 return Err(NativeParseError::MissingOperand { operator, span });
876 }
877 };
878 if matches!(
879 "ed.token,
880 TokenTree::Literal(literal)
881 if matches!(literal.kind, LiteralKind::String | LiteralKind::RawString)
882 ) {
883 return Err(unexpected!(
884 quoted.token,
885 "a quoted token other than a string literal"
886 ));
887 }
888 let quoted_span = quoted.token.expect_span();
889 let Some(quoted_text) = quoted.token.spelling().map(str::to_owned) else {
890 return Err(unexpected!(quoted.token, "a quoted token"));
891 };
892 let quoted = typed_terminal(
893 Symbol::new(quoted_text, quoted_span),
894 quoted.trailing_trivia,
895 );
896 if is_token!(&token.token, symbol) {
897 Expr!(Quote::Symbol {
898 specifier: typed_token(token),
899 symbol: quoted,
900 })
901 } else if is_token!(&token.token, local) {
902 Expr!(Quote::Local {
903 specifier: typed_token(token),
904 symbol: quoted,
905 })
906 } else if is_token!(&token.token, global) {
907 Expr!(Quote::Global {
908 specifier: typed_token(token),
909 symbol: quoted,
910 })
911 } else if is_token!(&token.token, threadVariable) {
912 Expr!(Quote::ThreadVariable {
913 specifier: typed_token(token),
914 symbol: quoted,
915 })
916 } else if is_token!(&token.token, threadLocal) {
917 Expr!(Quote::ThreadLocal {
918 specifier: typed_token(token),
919 symbol: quoted,
920 })
921 } else {
922 unreachable!("quote actions are assigned only to quote specifiers")
923 }
924 }
925 UnaryAction::Error => {
926 return Err(unexpected!(token.token, "an expression"));
927 }
928 };
929 self.accumulate(result, level)
930 }
931
932 fn parse_if_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
934 let condition = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
935 let then_keyword = self.consume_exact("then")?;
936 let then_value = self.required_clause_expression(PREC_CONTROL, &then_keyword.token)?;
937 let then_clause = ThenClause::new(typed_token(then_keyword), Box::new(then_value));
938 let else_clause = self
939 .take_exact("else")
940 .map(|else_keyword| {
941 let value = self.required_clause_expression(PREC_CONTROL, &else_keyword.token)?;
942 Ok::<_, NativeParseError>(ElseClause::new(
943 typed_token(else_keyword),
944 Box::new(value),
945 ))
946 })
947 .transpose()?;
948 Ok(Expr!(If {
949 if_token: typed_token(keyword),
950 condition: Box::new(condition),
951 then_clause,
952 else_clause,
953 }))
954 }
955
956 fn parse_for_loop(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
958 let variable = self.consume_symbol("a loop variable")?;
959
960 enum Domain {
961 Bare,
963 Range(Option<RangeBoundFrom>, Option<RangeBoundTo>),
965 In(SignificantToken, Box<Expr>),
967 }
968 let domain = if let Some(token) = self.take_exact("in") {
969 let collection = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
970 Domain::In(token, Box::new(collection))
971 } else {
972 let lower_bound = self
973 .take_exact("from")
974 .map(|token| {
975 let value = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
976 Ok::<_, NativeParseError>(RangeBoundFrom::new(
977 typed_token(token),
978 Box::new(value),
979 ))
980 })
981 .transpose()?;
982 let upper_bound = self
983 .take_exact("to")
984 .map(|token| {
985 let value = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
986 Ok::<_, NativeParseError>(RangeBoundTo::new(
987 typed_token(token),
988 Box::new(value),
989 ))
990 })
991 .transpose()?;
992 if lower_bound.is_some() || upper_bound.is_some() {
993 Domain::Range(lower_bound, upper_bound)
994 } else {
995 Domain::Bare
996 }
997 };
998
999 let when_condition = if let Some(token) = self.take_exact("when") {
1000 let condition = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
1001 Some(WhenCondition::new(typed_token(token), Box::new(condition)))
1002 } else {
1003 None
1004 };
1005 let body = self.parse_loop_body()?;
1006
1007 Ok(match domain {
1008 Domain::Bare => Expr!(For::Bare {
1009 for_token: typed_token(keyword),
1010 variable,
1011 condition: when_condition,
1012 body,
1013 }),
1014 Domain::Range(lower_bound, upper_bound) => Expr!(For::Range {
1015 for_token: typed_token(keyword),
1016 variable,
1017 lower_bound,
1018 upper_bound,
1019 condition: when_condition,
1020 body,
1021 }),
1022 Domain::In(token, collection) => Expr!(For::In {
1023 for_token: typed_token(keyword),
1024 variable,
1025 in_token: typed_token(token),
1026 collection,
1027 condition: when_condition,
1028 body,
1029 }),
1030 })
1031 }
1032
1033 fn parse_while_loop(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1035 let condition = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
1036 let body = self.parse_loop_body()?;
1037 Ok(Expr!(While {
1038 while_token: typed_token(keyword),
1039 condition: Box::new(condition),
1040 body,
1041 }))
1042 }
1043
1044 fn parse_loop_body(&mut self) -> Result<LoopBody, NativeParseError> {
1046 let (list_step, do_step) = if let Some(token) = self.take_exact("list") {
1047 let listed_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1048 let list_step = Some(ListStep::new(typed_token(token), Box::new(listed_value)));
1049 if let Some(token) = self.take_exact("do") {
1050 let ignored_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1051 (
1052 list_step,
1053 Some(DoStep::new(typed_token(token), Box::new(ignored_value))),
1054 )
1055 } else {
1056 (list_step, None)
1057 }
1058 } else if let Some(token) = self.take_exact("do") {
1059 let ignored_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1060 (
1061 None,
1062 Some(DoStep::new(typed_token(token), Box::new(ignored_value))),
1063 )
1064 } else {
1065 return Err(self.expected_at_lookahead("`list` or `do`"));
1066 };
1067
1068 Ok(LoopBody::new(list_step, do_step))
1069 }
1070
1071 fn parse_try_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1073 let value = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
1074 let then_clause = self
1075 .take_exact("then")
1076 .map(|then_keyword| {
1077 let value = self.required_clause_expression(PREC_CONTROL, &then_keyword.token)?;
1078 Ok::<_, NativeParseError>(ThenClause::new(
1079 typed_token(then_keyword),
1080 Box::new(value),
1081 ))
1082 })
1083 .transpose()?;
1084
1085 let fallback = if let Some(else_keyword) = self.take_exact("else") {
1086 let value = self.required_clause_expression(PREC_CONTROL, &else_keyword.token)?;
1087 Some(TryFallback::Else(ElseClause::new(
1088 typed_token(else_keyword),
1089 Box::new(value),
1090 )))
1091 } else if let Some(except_keyword) = self.take_exact("except") {
1092 let exception = self.consume_symbol("an exception symbol")?;
1093 let do_keyword = self.consume_exact("do")?;
1094 let value = self.required_clause_expression(PREC_CONTROL, &do_keyword.token)?;
1095 Some(TryFallback!(Except {
1096 except_token: typed_token(except_keyword),
1097 exception,
1098 do_token: typed_token(do_keyword),
1099 value: Box::new(value),
1100 }))
1101 } else {
1102 None
1103 };
1104
1105 Ok(Expr!(Try {
1106 try_token: typed_token(keyword),
1107 value: Box::new(value),
1108 on_success: then_clause,
1109 fallback,
1110 }))
1111 }
1112
1113 fn parse_new_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1115 let class = self.required_clause_expression(PREC_LOOP_CLAUSE, &keyword.token)?;
1116 let parent_class = if let Some(token) = self.take_exact("of") {
1117 let parent = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
1118 Some(OfClass::new(typed_token(token), Box::new(parent)))
1119 } else {
1120 None
1121 };
1122 let instance = if let Some(token) = self.take_exact("from") {
1123 let instance = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
1124 Some(FromInstance::new(typed_token(token), Box::new(instance)))
1125 } else {
1126 None
1127 };
1128
1129 Ok(Expr!(New {
1130 new_token: typed_token(keyword),
1131 class: Box::new(class),
1132 parent_class,
1133 instance,
1134 }))
1135 }
1136
1137 fn parse_debug_clause(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1139 let spelling = parsing_spelling(&keyword.token).to_owned();
1140 if matches!(
1141 spelling.as_str(),
1142 "time" | "timing" | "elapsedTime" | "elapsedTiming" | "profile"
1143 ) {
1144 let value = self
1145 .parse_required(PREC_CONTROL)
1146 .map_err(|error| error.missing_operand_for(&keyword.token))?;
1147 return Ok(match spelling.as_str() {
1148 "time" => Expr!(Profile::Time {
1149 modifier: typed_token(keyword),
1150 value: Box::new(value),
1151 }),
1152 "timing" => Expr!(Profile::Timing {
1153 modifier: typed_token(keyword),
1154 value: Box::new(value),
1155 }),
1156 "elapsedTime" => Expr!(Profile::ElapsedTime {
1157 modifier: typed_token(keyword),
1158 value: Box::new(value),
1159 }),
1160 "elapsedTiming" => Expr!(Profile::ElapsedTiming {
1161 modifier: typed_token(keyword),
1162 value: Box::new(value),
1163 }),
1164 "profile" => Expr!(Profile::Profile {
1165 modifier: typed_token(keyword),
1166 value: Box::new(value),
1167 }),
1168 _ => unreachable!(),
1169 });
1170 }
1171 let value_is_optional = matches!(spelling.as_str(), "step" | "finish");
1172 let value = if value_is_optional {
1173 self.parse_nullable(PREC_CONTROL)?
1174 } else {
1175 Some(
1176 self.parse_required(PREC_CONTROL)
1177 .map_err(|error| error.missing_operand_for(&keyword.token))?,
1178 )
1179 };
1180 let value = value.map(Box::new);
1181 Ok(match spelling.as_str() {
1182 "step" => Expr!(Debug::Step {
1183 keyword: typed_token(keyword),
1184 value,
1185 }),
1186 "finish" => Expr!(Debug::Finish {
1187 keyword: typed_token(keyword),
1188 value,
1189 }),
1190 "shield" => Expr!(Debug::Shield {
1191 keyword: typed_token(keyword),
1192 value,
1193 }),
1194 "TEST" => Expr!(Debug::Test {
1195 keyword: typed_token(keyword),
1196 value,
1197 }),
1198 "breakpoint" => Expr!(Debug::Breakpoint {
1199 keyword: typed_token(keyword),
1200 value,
1201 }),
1202 _ => unreachable!("debug actions are assigned only to debug keywords"),
1203 })
1204 }
1205
1206 fn required_clause_expression(
1208 &mut self,
1209 level: u8,
1210 keyword: &TokenTree,
1211 ) -> Result<Expr, NativeParseError> {
1212 match self.parse_nullable(level)? {
1213 None => Err(NativeParseError::MissingOperand {
1214 operator: keyword.description(),
1215 span: keyword.expect_span(),
1216 }),
1217 Some(expression) => Ok(expression),
1218 }
1219 }
1220
1221 fn consume_symbol(&mut self, expected: &'static str) -> Result<Symbol, NativeParseError> {
1223 match self.consume() {
1224 Lookahead::Token(token)
1225 if matches!(token.token, TokenTree::Ident(_))
1226 && matches!(parse_info(&token.token).unary, UnaryAction::Atom) =>
1227 {
1228 let span = token.token.expect_span();
1229 let text = token.token.description();
1230 Ok(typed_terminal(
1231 Symbol::new(text, span),
1232 token.trailing_trivia,
1233 ))
1234 }
1235 Lookahead::Token(token) => Err(unexpected!(token.token, expected)),
1236 Lookahead::End(span) => Err(NativeParseError::unexpected_end(expected, span)),
1237 }
1238 }
1239
1240 fn consume_exact(
1242 &mut self,
1243 spelling: &'static str,
1244 ) -> Result<SignificantToken, NativeParseError> {
1245 match self.consume() {
1246 Lookahead::Token(token) if parsing_spelling(&token.token) == spelling => Ok(token),
1247 Lookahead::Token(token) => Err(unexpected!(token.token, spelling)),
1248 Lookahead::End(span) => Err(NativeParseError::unexpected_end(spelling, span)),
1249 }
1250 }
1251
1252 fn take_exact(&mut self, spelling: &'static str) -> Option<SignificantToken> {
1254 if matches!(
1255 self.peek(),
1256 Lookahead::Token(token)
1257 if parsing_spelling(&token.token) == spelling
1258 ) {
1259 let Lookahead::Token(token) = self.consume() else {
1260 unreachable!("the token just peeked is consumable")
1261 };
1262 Some(token)
1263 } else {
1264 None
1265 }
1266 }
1267
1268 fn expected_at_lookahead(&self, expected: &'static str) -> NativeParseError {
1270 match self.peek() {
1271 Lookahead::Token(token) => unexpected!(token.token, expected),
1272 Lookahead::End(span) => NativeParseError::unexpected_end(expected, span),
1273 }
1274 }
1275
1276 fn accumulate(&mut self, mut left: Expr, level: u8) -> Result<Expr, NativeParseError> {
1278 loop {
1279 let Lookahead::Token(next) = self.peek() else {
1280 return Ok(left);
1281 };
1282 let info = if matches!(&next.token, TokenTree::Punct(punct) if punct.text().is_empty())
1283 {
1284 self.adjacency_info()
1285 } else {
1286 parse_info(&next.token)
1287 };
1288 if info.precedence <= level {
1289 return Ok(left);
1290 }
1291 let Lookahead::Token(operator) = self.consume() else {
1292 unreachable!("the token just peeked is consumable")
1293 };
1294 left = if matches!(&operator.token, TokenTree::Punct(punct) if punct.text().is_empty())
1295 {
1296 let right = self
1297 .parse_required(PREC_APPLICATION_RIGHT)
1298 .map_err(|error| error.missing_operand_for(&operator.token))?;
1299 let adjacency = typed_terminal(
1300 Adj::new("", operator.token.expect_span()),
1301 operator.trailing_trivia,
1302 );
1303 Expr!(Op::Bin::Adj {
1304 left_operand: Box::new(left),
1305 operator: adjacency,
1306 right_operand: Box::new(right),
1307 })
1308 } else if let Some(strength) = info.binary_strength {
1309 let left = BinaryLeft::prepare(left, &operator.token)?;
1310 let right = self
1311 .parse_required(strength)
1312 .map_err(|error| error.missing_operand_for(&operator.token))?;
1313 lower_binary(left, operator, right)?
1314 } else if info.postfix {
1315 let span = operator.token.expect_span();
1316 let spelling = operator.token.description();
1317 let operator = PostfixOperator::from_token_tree_with_trivia(
1318 operator.token,
1319 operator.trailing_trivia,
1320 )
1321 .ok_or(NativeParseError::Unsupported {
1322 syntax: spelling,
1323 span,
1324 })?;
1325 Expr!(Op::Postfix {
1326 operand: Box::new(left),
1327 operator,
1328 })
1329 } else if !matches!(info.unary, UnaryAction::Error) {
1330 if operator.crossed_newline {
1331 return Err(NativeParseError::NewlineInApplication {
1332 span: operator.token.expect_span(),
1333 });
1334 }
1335 let adjacency_span = operator.token.expect_span().subspan(0, 0);
1336 let right = self.parse_consumed(operator, PREC_APPLICATION_RIGHT)?;
1337 Expr!(Op::Bin::Adj {
1338 left_operand: Box::new(left),
1339 operator: Adj::new("", adjacency_span),
1340 right_operand: Box::new(right),
1341 })
1342 } else {
1343 return Err(unexpected!(operator.token, "an operator"));
1344 };
1345 }
1346 }
1347
1348 fn adjacency_info(&self) -> ParseInfo {
1350 let mut input = self.input.fork();
1351 let _ = input.next_significant();
1352 input.next_significant().map_or_else(
1353 || ParseInfo::stop(PREC_APPLICATION),
1354 |right| ParseInfo::binary(parse_info(&right.token).precedence, PREC_APPLICATION_RIGHT),
1355 )
1356 }
1357
1358 fn only_expression(&self, components: Components<Component>) -> Result<Expr, NativeParseError> {
1360 if components.is_punctuated() {
1361 return Err(NativeParseError::Unexpected {
1362 found: "a sequence".into(),
1363 expected: "one expression",
1364 span: components.first.expect_span(),
1365 });
1366 }
1367 match components.first {
1368 Component::Expr(value) => Ok(*value),
1369 value => Err(NativeParseError::Unexpected {
1370 found: "an empty component".into(),
1371 expected: "one expression",
1372 span: value.expect_span(),
1373 }),
1374 }
1375 }
1376
1377 fn packed_content(
1379 &self,
1380 components: Components<Component>,
1381 ) -> Result<PackedContent, NativeParseError> {
1382 match components.into_punctuated() {
1383 Ok(components) => Ok(ExprPack::new(components).into()),
1384 Err(Component::Expr(expression)) => Ok((*expression).into()),
1385 Err(value) => Err(NativeParseError::Unexpected {
1386 found: "an empty component".into(),
1387 expected: "one expression",
1388 span: value.expect_span(),
1389 }),
1390 }
1391 }
1392
1393 fn peek(&self) -> Lookahead {
1395 self.input.lookahead()
1396 }
1397
1398 fn consume(&mut self) -> Lookahead {
1400 self.input.consume_lookahead()
1401 }
1402
1403 fn skip_trivia(&mut self) {
1405 self.input.skip_trivia();
1406 }
1407
1408 fn at_end(&self) -> bool {
1410 matches!(self.peek(), Lookahead::End(_))
1411 }
1412
1413 fn at_punctuation(&self, spelling: &str) -> bool {
1415 matches!(
1416 self.peek(),
1417 Lookahead::Token(token)
1418 if token.token.spelling() == Some(spelling)
1419 )
1420 }
1421
1422 fn take_punctuation(&mut self, spelling: &str) -> Option<SignificantToken> {
1424 if !self.at_punctuation(spelling) {
1425 return None;
1426 }
1427 let Lookahead::Token(token) = self.consume() else {
1428 unreachable!("the punctuation just peeked is consumable")
1429 };
1430 Some(token)
1431 }
1432}
1433
1434fn parse_delimited(token: SignificantToken) -> Result<Expr, NativeParseError> {
1436 let group_trailing = token.trailing_trivia;
1437 let group = match token.token {
1438 TokenTree::Group(group) => group,
1439 token => return Err(unexpected!(token, "a delimited group")),
1440 };
1441 let kind = group.delim_kind();
1442 let delimiter_spans = group.delimiter().spans.clone();
1443 let mut group_contents = group.into_stream();
1444 let opening_trivia = group_contents.take_leading_trivia();
1445 let mut contents = Engine::new(group_contents);
1446 let mut muted = Vec::new();
1447 let elements = loop {
1448 let elements = contents.parse_optional_components()?;
1449 let Some(separator) = contents.take_punctuation(";") else {
1450 break elements;
1451 };
1452 let Some(elements) = elements else {
1453 return Err(unexpected!(separator.token, "a statement before `;`"));
1454 };
1455 muted.push(Statement::new(
1456 contents.packed_content(elements)?,
1457 typed_token(separator),
1458 ));
1459 };
1460 if let Lookahead::Token(token) = contents.peek() {
1461 return Err(unexpected!(token.token, "the end of the group"));
1462 }
1463
1464 let expression: Expr = match kind {
1465 DelimiterKind::Bracket => {
1466 let elements = elements
1467 .map(|elements| contents.packed_content(elements))
1468 .transpose()?;
1469 let mut value = Array::new(muted, elements);
1470 value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1471 value.into()
1472 }
1473 DelimiterKind::Brace => {
1474 let elements = elements
1475 .map(|elements| contents.packed_content(elements))
1476 .transpose()?;
1477 let mut value = List::new(muted, elements);
1478 value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1479 value.into()
1480 }
1481 DelimiterKind::AngleBar => {
1482 let elements = elements
1483 .map(|elements| contents.packed_content(elements))
1484 .transpose()?;
1485 let mut value = AngleBarList::new(muted, elements);
1486 value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1487 value.into()
1488 }
1489 DelimiterKind::Parenthesis if muted.is_empty() && elements.is_none() => {
1490 let mut value = Sequence::new(Vec::new(), None);
1491 value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1492 value.into()
1493 }
1494 DelimiterKind::Parenthesis
1495 if !muted.is_empty() || elements.as_ref().is_some_and(Components::is_punctuated) =>
1496 {
1497 let mut value = if elements.as_ref().is_some_and(Components::is_punctuated) {
1498 Sequence::new(
1499 muted,
1500 elements
1501 .map(|elements| contents.packed_content(elements))
1502 .transpose()?,
1503 )
1504 } else {
1505 let value = elements
1506 .map(|elements| contents.only_expression(elements))
1507 .transpose()?;
1508 let mut value = Holder::new(muted, value.map(Box::new));
1509 value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1510 return Ok(value.into());
1511 };
1512 value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1513 value.into()
1514 }
1515 DelimiterKind::Parenthesis => {
1516 let value = elements
1517 .map(|elements| contents.only_expression(elements))
1518 .transpose()?;
1519 let mut value = Holder::new(Vec::new(), value.map(Box::new));
1520 value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1521 value.into()
1522 }
1523 };
1524 Ok(expression)
1525}
1526
1527fn typed_delimiter<D: DelimiterToken>(
1529 spans: crate::DoubleSpan,
1530 opening_trivia: TrailingTrivia,
1531 closing_trivia: TrailingTrivia,
1532) -> D {
1533 let mut delimiter = D::new(spans);
1534 *delimiter.opening_trivia_mut() = opening_trivia;
1535 *delimiter.closing_trivia_mut() = closing_trivia;
1536 delimiter
1537}
1538
1539fn lower_prefix_statement(keyword: SignificantToken, value: Option<Expr>) -> Expr {
1541 if is_token!(&keyword.token, break) {
1542 Expr!(Control::Break {
1543 break_token: typed_token(keyword),
1544 value: value.map(Box::new),
1545 })
1546 } else if is_token!(&keyword.token, continue) {
1547 Expr!(Control::Continue {
1548 continue_token: typed_token(keyword),
1549 value: value.map(Box::new),
1550 })
1551 } else if is_token!(&keyword.token, return) {
1552 Expr!(Control::Return {
1553 return_token: typed_token(keyword),
1554 value: value.map(Box::new),
1555 })
1556 } else {
1557 let value = value.expect("catch, throw, and trap require a value");
1558 if is_token!(&keyword.token, catch) {
1559 Expr!(Catch {
1560 catch_token: typed_token(keyword),
1561 value: Box::new(value),
1562 })
1563 } else if is_token!(&keyword.token, throw) {
1564 Expr!(Throw {
1565 throw_token: typed_token(keyword),
1566 value: Box::new(value),
1567 })
1568 } else if is_token!(&keyword.token, trap) {
1569 Expr!(Trap {
1570 trap_token: typed_token(keyword),
1571 value: Box::new(value),
1572 })
1573 } else {
1574 unreachable!("statement actions are assigned only to statement keywords")
1575 }
1576 }
1577}
1578
1579fn lower_atom(token: SignificantToken) -> Result<Expr, NativeParseError> {
1581 match token.token {
1582 TokenTree::Ident(raw) => Ok(typed_terminal(
1583 Symbol::new(raw.text(), raw.expect_span()),
1584 token.trailing_trivia,
1585 )
1586 .into()),
1587 TokenTree::Literal(raw) => {
1588 let span = raw.expect_span();
1589 Ok(match raw.kind {
1590 LiteralKind::Integer => {
1591 typed_terminal(IntegerLiteral::new(raw.text(), span), token.trailing_trivia)
1592 .into()
1593 }
1594 LiteralKind::Float => {
1595 typed_terminal(FloatLiteral::new(raw.text(), span), token.trailing_trivia)
1596 .into()
1597 }
1598 LiteralKind::String => {
1599 lower_string_literal(raw.text(), span, token.trailing_trivia)
1600 }
1601 LiteralKind::RawString => {
1602 lower_raw_string_literal(raw.text(), span, token.trailing_trivia)
1603 }
1604 })
1605 }
1606 token => Err(unexpected!(token, "an expression")),
1607 }
1608}
1609
1610enum BinaryLeft {
1612 Expression(Box<Expr>),
1614 Assignment {
1616 target: AssignmentTarget,
1618 local: bool,
1620 },
1621 Lambda(LambdaArguments),
1623}
1624
1625pub(crate) enum LambdaArguments {
1627 Variadic(Symbol),
1629 List(Box<Delimited<Option<ArgumentListContent>>>),
1631}
1632
1633impl BinaryLeft {
1634 fn prepare(left: Expr, operator: &TokenTree) -> Result<Self, NativeParseError> {
1636 let span = operator.expect_span();
1637 Ok(match operator.spelling() {
1638 Some("=") => Self::Assignment {
1639 target: AssignmentTarget::parse(left, false, span)?,
1640 local: false,
1641 },
1642 Some(":=") => Self::Assignment {
1643 target: AssignmentTarget::parse(left, true, span)?,
1644 local: true,
1645 },
1646 Some("->") => Self::Lambda(
1647 lambda_arguments(left).ok_or(NativeParseError::InvalidLambdaArguments { span })?,
1648 ),
1649 _ => Self::Expression(Box::new(left)),
1650 })
1651 }
1652}
1653
1654enum AssignmentTarget {
1656 Symbol(Symbol),
1658 Operator(ExprOp),
1660 New(ExprNew),
1662 List(Box<AssignmentList>),
1664}
1665
1666impl AssignmentTarget {
1667 fn parse(expression: Expr, local: bool, span: Span) -> Result<Self, NativeParseError> {
1669 match expression {
1670 Expr::Symbol(variable) => Ok(Self::Symbol(variable)),
1671 Expr::Op(expression) => Ok(Self::Operator(expression)),
1672 Expr::New(statement) if local => Ok(Self::New(statement)),
1673 expression => assignment_list(expression)
1674 .map(Box::new)
1675 .map(Self::List)
1676 .ok_or(NativeParseError::InvalidAssignmentTarget { span }),
1677 }
1678 }
1679}
1680
1681fn lower_binary(
1683 left: BinaryLeft,
1684 operator: SignificantToken,
1685 right: Expr,
1686) -> Result<Expr, NativeParseError> {
1687 let span = operator.token.expect_span();
1688 let spelling = operator
1689 .token
1690 .spelling()
1691 .expect("binary actions are assigned only to spelled tokens");
1692 match left {
1693 BinaryLeft::Assignment { target, local } => {
1694 Ok(lower_assignment(target, operator, right, local))
1695 }
1696 BinaryLeft::Lambda(arguments) => Ok(match arguments {
1697 LambdaArguments::Variadic(argument) => Expr!(Lambda::Variadic {
1698 argument,
1699 operator: typed_token(operator),
1700 body: Box::new(right),
1701 }),
1702 LambdaArguments::List(arguments) => Expr!(Lambda::List {
1703 arguments: *arguments,
1704 operator: typed_token(operator),
1705 body: Box::new(right),
1706 }),
1707 }),
1708 BinaryLeft::Expression(left) if spelling == "<-" => Ok(Expr!(Assign::Evaluated {
1709 evaluated_domain: left,
1710 operator: typed_token(operator),
1711 value: Box::new(right),
1712 })),
1713 BinaryLeft::Expression(left) if spelling == "=>" => Ok(Expr!(Option {
1714 key: left,
1715 operator: typed_token(operator),
1716 value: Box::new(right),
1717 })),
1718 BinaryLeft::Expression(left)
1719 if GENERATED_AUGMENTED_OPERATOR_SPELLINGS.contains(&spelling) =>
1720 {
1721 let operator = AugmentedOperator::from_token_tree_with_trivia(
1722 operator.token,
1723 operator.trailing_trivia,
1724 )
1725 .expect("the augmented operator table and category have the same source");
1726 Ok(Expr!(Assign::Augmented {
1727 target: left,
1728 operator,
1729 value: Box::new(right),
1730 }))
1731 }
1732 BinaryLeft::Expression(left) if matches!(spelling, "." | ".?") => Ok(match spelling {
1733 "." => Expr!(Op::Bin::Member::Dot {
1734 receiver: left,
1735 operator: typed_token::<Token![.]>(operator),
1736 member: Box::new(right),
1737 }),
1738 ".?" => Expr!(Op::Bin::Member::Optional {
1739 receiver: left,
1740 operator: typed_token::<Token![.?]>(operator),
1741 member: Box::new(right),
1742 }),
1743 _ => unreachable!(),
1744 }),
1745 BinaryLeft::Expression(left) if spelling == "#" => Ok(Expr!(Op::Bin::Index {
1746 receiver: left,
1747 operator: typed_token(operator),
1748 index: Box::new(right),
1749 })),
1750 BinaryLeft::Expression(left) => {
1751 let spelling = spelling.to_owned();
1752 let operator = BinaryOperator::from_token_tree_with_trivia(
1753 operator.token,
1754 operator.trailing_trivia,
1755 )
1756 .ok_or(NativeParseError::Unsupported {
1757 syntax: spelling,
1758 span,
1759 })?;
1760 Ok(Expr!(Op::Bin::Regular {
1761 left_operand: left,
1762 operator,
1763 right_operand: Box::new(right),
1764 }))
1765 }
1766 }
1767}
1768
1769fn lower_assignment(
1771 target: AssignmentTarget,
1772 operator: SignificantToken,
1773 right: Expr,
1774 local: bool,
1775) -> Expr {
1776 match (local, target) {
1777 (false, AssignmentTarget::Symbol(variable)) => {
1778 Expr!(Assign::Simple::Global {
1779 variable,
1780 operator: typed_token(operator),
1781 value: Box::new(right),
1782 })
1783 }
1784 (true, AssignmentTarget::Symbol(variable)) => {
1785 Expr!(Assign::Simple::Local {
1786 variable,
1787 operator: typed_token(operator),
1788 value: Box::new(right),
1789 })
1790 }
1791 (false, AssignmentTarget::Operator(argument_expr)) => {
1792 Expr!(Assign::Op {
1793 argument_expr,
1794 operator: typed_token(operator),
1795 value_expr: Box::new(right),
1796 })
1797 }
1798 (true, AssignmentTarget::Operator(ExprOp::Bin(ExprOpBin::Adj(application)))) => {
1799 let (typical_value, function) = installation_value(right);
1800 Expr!(Assign::Install::Method {
1801 method: application.left_operand,
1802 operator: application.operator,
1803 signature: application.right_operand,
1804 assign_op: typed_token(operator),
1805 typical_value,
1806 function: Box::new(function),
1807 })
1808 }
1809 (true, AssignmentTarget::Operator(domain_expr)) => {
1810 let (typical_value, function) = installation_value(right);
1811 Expr!(Assign::Install::Op {
1812 domain_expr,
1813 assign_op: typed_token(operator),
1814 typical_value,
1815 function: Box::new(function),
1816 })
1817 }
1818 (true, AssignmentTarget::New(new_statement)) => {
1819 Expr!(Assign::Install::New {
1820 new_statement,
1821 operator: typed_token(operator),
1822 function: Box::new(right),
1823 })
1824 }
1825 (local, AssignmentTarget::List(argument_list)) => {
1826 if local {
1827 Expr!(Assign::Parallel::Local {
1828 argument_list,
1829 operator: typed_token(operator),
1830 value: Box::new(right),
1831 })
1832 } else {
1833 Expr!(Assign::Parallel::Global {
1834 argument_list,
1835 operator: typed_token(operator),
1836 value: Box::new(right),
1837 })
1838 }
1839 }
1840 (false, AssignmentTarget::New(_)) => {
1841 unreachable!("global assignment preparation rejects new statements")
1842 }
1843 }
1844}
1845
1846pub(crate) fn installation_value(value: Expr) -> (Option<TypeAnnotation>, Expr) {
1848 match value {
1849 Expr::Option(value) => (
1850 Some(TypeAnnotation::new(value.key, value.operator)),
1851 *value.value,
1852 ),
1853 value => (None, value),
1854 }
1855}
1856
1857fn parse_cell_stream(cells: CellStream) -> Result<SourceFile, NativeParseError> {
1859 let mut elements = Vec::new();
1860 let bof_span = cells.physical_bof();
1861 let eof_span = cells.physical_eof();
1862 let mut detached = Vec::new();
1865 let mut cells = cells.into_iter().peekable();
1866 while let Some(cell) = cells.next() {
1867 if cell.is_empty() {
1868 detached.extend(CommentTrivia::of(&cell.into_parser_token_stream()).into_trivia());
1869 continue;
1870 }
1871 let eoc = cells
1872 .peek()
1873 .and_then(cell_start_span)
1874 .unwrap_or_else(|| end_span(&cell));
1875 if let Some(element) = parse_raw_cell_at(cell, eoc, std::mem::take(&mut detached))? {
1876 elements.push(element);
1877 }
1878 }
1879 let mut source_file = SourceFile::new(BOF::new("", bof_span), elements, EOF::new("", eof_span));
1880 source_file.set_closing_comments(detached);
1881 Ok(source_file)
1882}
1883
1884fn tokenize_for_native_parser(tokens: TokenStream) -> Result<CellStream, NativeParseError> {
1886 match tokens.to_cell_stream() {
1887 Ok(cells) => Ok(cells),
1888 Err(tokenize_error) => {
1889 let incomplete = frame_recovering(tokens).incomplete;
1890 if let Some(cell) = incomplete
1891 && let Err(parse_error) = parse_raw_cell(cell)
1892 {
1893 return Err(parse_error);
1894 }
1895 Err(NativeParseError::Tokenize(tokenize_error))
1896 }
1897 }
1898}
1899
1900pub(crate) fn parse_raw_cell(
1902 tokens: CellTokenStream,
1903) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
1904 let eoc = end_span(&tokens);
1905 parse_raw_cell_at(tokens, eoc, Vec::new())
1906}
1907
1908fn parse_raw_cell_at(
1913 tokens: CellTokenStream,
1914 eoc: Span,
1915 mut detached: Vec<Trivia>,
1916) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
1917 let ends_with_semicolon = ends_with_cell_semicolon(&tokens);
1918 let mut tokens = tokens.into_parser_token_stream();
1919 detached.extend(tokens.take_prefix_trivia().into_vec());
1920 let semicolon = ends_with_semicolon
1921 .then(|| tokens.take_final_punctuation(";"))
1922 .flatten()
1923 .map(|(punctuation, trailing_trivia)| {
1924 <Token![;] as Token>::from_token_tree_with_trivia(
1925 TokenTree::Punct(punctuation),
1926 trailing_trivia,
1927 )
1928 .expect("a semicolon punctuation token lowers to Token![;]")
1929 });
1930 let mut cell = Engine::new(tokens).parse_cell(semicolon, eoc)?;
1931 if let Some(cell) = &mut cell {
1932 cell.leading_trivia = LeadingTrivia::new(detached);
1933 }
1934 Ok(cell)
1935}
1936
1937fn cell_start_span(tokens: &CellTokenStream) -> Option<Span> {
1939 let token = tokens.iter().next()?;
1940 let span = token
1941 .leading_trivia()
1942 .first()
1943 .map_or_else(|| token.span(), Spanned::span);
1944 span.start().map(|start| span.at(start))
1945}
1946
1947impl Parse for Expr {
1948 fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1949 let tokens = input.by_ref().collect::<TokenStream>();
1950 let mut engine = Engine::new(tokens);
1951 engine.skip_trivia();
1952 let value = engine
1953 .parse_required(PREC_CLOSER)
1954 .map_err(token_parse_error)?;
1955 engine.skip_trivia();
1956 match engine.peek() {
1957 Lookahead::End(_) => Ok(value),
1958 Lookahead::Token(token) => Err(TokenParseError::TrailingToken {
1959 found: token.token.description(),
1960 span: token.token.expect_span(),
1961 }),
1962 }
1963 }
1964}
1965
1966impl Parse for SourceFile {
1967 fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1968 let tokens = input.by_ref().collect();
1969 tokenize_for_native_parser(tokens)
1970 .and_then(parse_cell_stream)
1971 .map_err(token_parse_error)
1972 }
1973}
1974
1975fn token_parse_error(error: NativeParseError) -> TokenParseError {
1977 let span = error.expect_span();
1978 TokenParseError::Syntax {
1979 message: error.to_string(),
1980 span,
1981 }
1982}
1983
1984fn parsing_spelling(token: &TokenTree) -> &str {
1986 token.spelling().map_or("", canonical_word_spelling)
1987}
1988
1989fn typed_token<T: Token>(token: SignificantToken) -> T {
1991 let spelling = token.token.description();
1992 T::from_token_tree_with_trivia(token.token, token.trailing_trivia)
1993 .unwrap_or_else(|| panic!("`{spelling}` cannot be lowered to `{}`", T::SPELLING))
1994}
1995
1996fn typed_terminal<T: Terminal>(mut terminal: T, trailing_trivia: TrailingTrivia) -> T {
1998 *terminal.trailing_trivia_mut() = trailing_trivia;
1999 terminal
2000}
2001
2002fn empty_span_at(lookahead: &Span) -> Span {
2004 lookahead.subspan(0, 0)
2005}
2006
2007fn lower_string_literal(text: &str, span: Span, trailing_trivia: TrailingTrivia) -> Expr {
2009 let body_end = if text.len() > 1 && text.ends_with('"') {
2010 text.len() - 1
2011 } else {
2012 text.len()
2013 };
2014 let body = &text[1..body_end];
2015 let mut elements = Vec::new();
2016 let mut content_start = 0;
2017 let mut cursor = 0;
2018
2019 while cursor < body.len() {
2020 if body.as_bytes()[cursor] != b'\\' {
2021 cursor += 1;
2022 continue;
2023 }
2024 if content_start < cursor {
2025 elements.push(StringElement::Content(StringContent::new(
2026 &body[content_start..cursor],
2027 span.subspan(content_start + 1, cursor + 1),
2028 )));
2029 }
2030 let escape_end = match body.as_bytes()[cursor + 1] {
2031 b'x' => cursor + 4,
2032 b'u' => cursor + 6,
2033 b'0'..=b'7' => {
2034 let mut end = cursor + 2;
2035 while end < body.len()
2036 && end < cursor + 4
2037 && body.as_bytes()[end].is_ascii_digit()
2038 && body.as_bytes()[end] < b'8'
2039 {
2040 end += 1;
2041 }
2042 end
2043 }
2044 _ => cursor + 2,
2045 };
2046 elements.push(StringElement::Escape(EscapeSequence::new(
2047 &body[cursor..escape_end],
2048 span.subspan(cursor + 1, escape_end + 1),
2049 )));
2050 cursor = escape_end;
2051 content_start = cursor;
2052 }
2053 if content_start < body.len() {
2054 elements.push(StringElement::Content(StringContent::new(
2055 &body[content_start..],
2056 span.subspan(content_start + 1, body_end),
2057 )));
2058 }
2059 typed_terminal(StringLiteral::new(elements, span), trailing_trivia).into()
2060}
2061
2062fn lower_raw_string_literal(text: &str, span: Span, trailing_trivia: TrailingTrivia) -> Expr {
2064 let body_end = if text.len() >= 6 && text.ends_with("///") {
2065 text.len() - 3
2066 } else {
2067 text.len()
2068 };
2069 let body = &text[3..body_end];
2070 let mut elements = Vec::new();
2071 let mut content_start = 0;
2072 let mut cursor = 0;
2073
2074 while cursor + 1 < body.len() {
2075 if &body.as_bytes()[cursor..cursor + 2] != b"//" {
2076 cursor += 1;
2077 continue;
2078 }
2079 if content_start < cursor {
2080 elements.push(RawStringElement::Content(RawStringContent::new(
2081 &body[content_start..cursor],
2082 span.subspan(content_start + 3, cursor + 3),
2083 )));
2084 }
2085 elements.push(RawStringElement::Escape(EscapeSequence::new(
2086 "//",
2087 span.subspan(cursor + 3, cursor + 5),
2088 )));
2089 cursor += 2;
2090 content_start = cursor;
2091 }
2092 if content_start < body.len() {
2093 elements.push(RawStringElement::Content(RawStringContent::new(
2094 &body[content_start..],
2095 span.subspan(content_start + 3, body_end),
2096 )));
2097 }
2098 typed_terminal(RawStringLiteral::new(elements, span), trailing_trivia).into()
2099}
2100
2101fn collection_contents(expression: Expr) -> Option<(crate::Delimiter, Option<PackedContent>)> {
2103 match expression {
2104 Expr::Collection(ExprCollection::Sequence(value)) if value.statements.is_empty() => {
2105 Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2106 }
2107 Expr::Collection(ExprCollection::List(value)) if value.statements.is_empty() => {
2108 Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2109 }
2110 Expr::Collection(ExprCollection::Array(value)) if value.statements.is_empty() => {
2111 Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2112 }
2113 Expr::Collection(ExprCollection::AngleBar(value)) if value.statements.is_empty() => {
2114 Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2115 }
2116 Expr::Holder(value) if value.muted.is_empty() => {
2117 let elements = value.value.map(|value| (*value).into());
2118 Some((DelimiterValue::delimiter(&value.delimiter), elements))
2119 }
2120 _ => None,
2121 }
2122}
2123
2124pub(crate) fn assignment_list(expression: Expr) -> Option<AssignmentList> {
2126 let (delimiter, elements) = collection_contents(expression)?;
2127 let contents = match elements {
2128 Some(elements) => {
2129 let components = packed_components(elements).map(assignment_argument)?;
2130 Some(match components.into_punctuated() {
2131 Ok(arguments) => AssignmentListContent!(Pack { arguments }),
2132 Err(argument) => argument.into(),
2133 })
2134 }
2135 None => None,
2136 };
2137 Some(AssignmentList::new(Delimited::new(delimiter, contents)))
2138}
2139
2140fn assignment_argument(component: Component) -> Option<AssignmentArgument> {
2142 match component {
2143 Component::Empty(value) => Some(AssignmentArgument::Empty(value)),
2144 Component::Expr(value) => match *value {
2145 Expr::Symbol(value) => Some(AssignmentArgument::Symbol(value)),
2146 Expr::Op(value) => Some(AssignmentArgument::Op(value)),
2147 Expr::Assign(ExprAssign::Evaluated(value)) => {
2148 Some(AssignmentArgument::Evaluated(value))
2149 }
2150 value => assignment_list(value).map(Into::into),
2151 },
2152 }
2153}
2154
2155fn expr_pack_symbols(elements: ExprPack) -> Option<Punctuated<Symbol>> {
2157 elements
2158 .pack
2159 .try_map(
2160 |component| match component {
2161 Component::Expr(value) => match *value {
2162 Expr::Symbol(value) => Ok(value),
2163 _ => Err(()),
2164 },
2165 Component::Empty(_) => Err(()),
2166 },
2167 Ok,
2168 )
2169 .ok()
2170}
2171
2172fn packed_components(content: PackedContent) -> Components<Component> {
2174 match content {
2175 PackedContent::Expr(expression) => Components {
2176 first: Component::Expr(expression),
2177 rest: Vec::new(),
2178 },
2179 PackedContent::Pack(pack) => Components::from_punctuated(pack.pack),
2180 }
2181}
2182
2183pub(crate) fn lambda_arguments(expression: Expr) -> Option<LambdaArguments> {
2185 match expression {
2186 Expr::Symbol(value) => Some(LambdaArguments::Variadic(value)),
2187 expression => {
2188 let (delimiter, elements) = collection_contents(expression)?;
2189 let arguments = match elements {
2190 Some(PackedContent::Expr(expression)) => match *expression {
2191 Expr::Symbol(value) => Some(ArgumentListContent::Symbol(value)),
2192 _ => return None,
2193 },
2194 Some(PackedContent::Pack(pack)) => Some(ArgumentListContent!(Pack {
2195 arguments: expr_pack_symbols(pack)?,
2196 })),
2197 None => None,
2198 };
2199 Some(LambdaArguments::List(Box::new(Delimited::new(
2200 delimiter, arguments,
2201 ))))
2202 }
2203 }
2204}
2205
2206fn token_parse_rule(spelling: &str) -> Option<TokenParseRule> {
2208 TOKEN_PARSE_RULES
2209 .binary_search_by_key(&spelling, |(declared, _)| *declared)
2210 .ok()
2211 .map(|index| TOKEN_PARSE_RULES[index].1)
2212}
2213
2214fn keyword_action(spelling: &str) -> Option<UnaryAction> {
2216 Some(match spelling {
2217 "break" | "continue" | "return" | "catch" | "throw" | "trap" => UnaryAction::Statement,
2218 "if" | "while" | "try" | "for" | "new" => UnaryAction::Control,
2219 "TEST" | "time" | "timing" | "elapsedTime" | "elapsedTiming" | "breakpoint" | "profile"
2220 | "shield" | "step" | "finish" => UnaryAction::Debug,
2221 "symbol" | "global" | "local" | "threadLocal" | "threadVariable" => UnaryAction::Quote,
2222 _ => return None,
2223 })
2224}
2225
2226fn parse_info(token: &TokenTree) -> ParseInfo {
2228 if matches!(token, TokenTree::Punct(punctuation) if punctuation.text().is_empty()) {
2229 return ParseInfo::binary(PREC_APPLICATION, PREC_APPLICATION_RIGHT);
2230 }
2231 if let TokenTree::Group(group) = token {
2232 return match group.delim_kind() {
2233 DelimiterKind::Bracket | DelimiterKind::AngleBar => {
2234 ParseInfo::delimiter(PREC_COLLECTION)
2235 }
2236 DelimiterKind::Parenthesis | DelimiterKind::Brace => {
2237 ParseInfo::delimiter(PREC_APPLICATION)
2238 }
2239 };
2240 }
2241
2242 let text = parsing_spelling(token);
2243 if let Some(rule) = token_parse_rule(text) {
2244 let mut info = ParseInfo::from(rule);
2245 if let Some(action) = keyword_action(text) {
2246 info.unary = action;
2247 }
2248 return info;
2249 }
2250
2251 match token {
2252 TokenTree::Ident(_) | TokenTree::Literal(_) => ParseInfo::atom(PREC_APPLICATION),
2253 _ => ParseInfo::stop(PREC_APPLICATION),
2254 }
2255}
2256
2257#[cfg(test)]
2258mod tests {
2259 use super::{NativeCellParser, NativeCellState, NativeParseError};
2260 use crate::cell_stream::frame_recovering;
2261 use crate::{NativeRealtimeParser, Spanned, lex_str, parse_native, parse_native_recovering};
2262
2263 #[test]
2267 fn cells_use_operator_clause_and_delimiter_state() {
2268 fn cells(source: &str) -> usize {
2269 let framed = frame_recovering(lex_str(source).unwrap());
2270 framed.cells.len() + usize::from(framed.incomplete.is_some())
2271 }
2272
2273 assert_eq!(cells("1\n2"), 2);
2274 assert_eq!(cells("1 +\n2"), 1);
2275 assert_eq!(cells("not\n1"), 1);
2276 assert_eq!(cells("1!\n2"), 2);
2277 assert_eq!(cells("if condition\nthen value"), 1);
2278 assert_eq!(cells("if condition\nthen value\nnext"), 2);
2279 assert_eq!(cells("symbol if\nnext"), 2);
2280 assert_eq!(cells("symbol +\nnext"), 2);
2281 assert_eq!(cells("1 -* comment\n*- 2"), 2);
2282 assert_eq!(cells("1 + -* comment\n*- 2"), 1);
2283 assert_eq!(cells("1;2"), 2);
2284 assert_eq!(cells("(1\n2;3)"), 1);
2287 assert_eq!(cells("symbol ;"), 1);
2289 }
2290
2291 #[test]
2292 fn invalid_binary_left_side_wins_over_a_missing_right_operand() {
2293 for (source, state, diagnostic, diagnostic_text) in [
2294 (
2295 "1 + 1 =",
2296 NativeCellState::Incomplete,
2297 "expected an operand after `=`, found end of input",
2298 "=",
2299 ),
2300 (
2301 "2 =",
2302 NativeCellState::Invalid,
2303 "invalid assignment target",
2304 "=",
2305 ),
2306 (
2307 "(x, y) ->",
2308 NativeCellState::Incomplete,
2309 "expected an operand after `->`, found end of input",
2310 "->",
2311 ),
2312 (
2313 "(x + y) ->",
2314 NativeCellState::Invalid,
2315 "invalid lambda argument list",
2316 "->",
2317 ),
2318 ] {
2319 let mut parser = NativeCellParser::new();
2320 assert_eq!(parser.push_line(source), state, "source: `{source}`");
2321 let error = parser
2322 .parse_error()
2323 .unwrap_or_else(|| panic!("expected a diagnostic for `{source}`"));
2324 assert_eq!(error.to_string(), diagnostic, "source: `{source}`");
2325 assert_eq!(error.span().text(), Some(diagnostic_text));
2326 }
2327 }
2328
2329 #[test]
2330 fn quote_modifiers_reject_string_literals_with_a_located_syntax_error() {
2331 for modifier in ["symbol", "local", "global", "threadLocal", "threadVariable"] {
2332 for literal in ["\"a\"", "///a///"] {
2333 let source = format!("{modifier} {literal}");
2334 for result in [
2335 parse_native(&source),
2336 parse_native_recovering(&source).map(|recovered| recovered.value),
2337 ] {
2338 let error = result.unwrap_err();
2339 assert!(
2340 matches!(error, NativeParseError::Unexpected { .. }),
2341 "{source}: {error}"
2342 );
2343 assert_eq!(error.span().text(), Some(literal), "{source}");
2344 assert_eq!(
2345 error.to_string(),
2346 format!(
2347 "expected a quoted token other than a string literal, found `{literal}`"
2348 ),
2349 "{source}",
2350 );
2351 }
2352 let mut parser = NativeCellParser::new();
2353 assert_eq!(
2354 parser.push_line(&source),
2355 NativeCellState::Invalid,
2356 "{source}"
2357 );
2358
2359 #[cfg(feature = "tree-sitter")]
2360 {
2361 assert!(crate::parse_file(&source).is_err(), "{source}");
2362 assert!(crate::parse_file_recovering(&source).is_err(), "{source}");
2363 }
2364 }
2365 }
2366 }
2367
2368 #[test]
2369 fn invalid_quoted_string_preserves_realtime_cells_and_trivia() {
2370 let source = "a = 1\nsymbol -- reason\n\"a\"\nb = 2";
2371 let parser = NativeRealtimeParser::new(source);
2372 assert_eq!(parser.state(), NativeCellState::Invalid);
2373 assert_eq!(parser.cells().len(), 3);
2374 let cells = parser.cells();
2375 assert_eq!(cells[0].state(), NativeCellState::Complete);
2376 assert_eq!(cells[1].state(), NativeCellState::Invalid);
2377 assert_eq!(cells[2].state(), NativeCellState::Complete);
2378 let error = cells[1].parse_error().unwrap();
2379 assert_eq!(error.span().text(), Some("\"a\""));
2380 assert_eq!(cells[1].tokens().to_string(), "symbol -- reason\n\"a\"");
2381 }
2382
2383 #[test]
2384 fn quote_modifiers_continue_to_accept_non_string_tokens() {
2385 for modifier in ["symbol", "local", "global", "threadLocal", "threadVariable"] {
2386 for token in ["a", "if", "symbol", "+", ";", "(", ")", "1", "1.5"] {
2387 let source = format!("{modifier} {token}");
2388 assert!(parse_native(&source).is_ok(), "{source}");
2389 }
2390 }
2391 }
2392}