1#![allow(clippy::result_large_err)]
4
5use std::sync::Arc;
6
7use miette::NamedSource;
8
9use cljrs_types::error::{CljxError, CljxResult};
10use cljrs_types::span::Span;
11
12use crate::form::{Form, FormKind};
13use crate::lexer::Lexer;
14use crate::namespaced_map;
15use crate::token::Token;
16
17fn map_arity_is_statically_odd(forms: &[Form]) -> bool {
25 let has_conditional = forms
26 .iter()
27 .any(|f| matches!(f.kind, FormKind::ReaderCond { .. }));
28 !has_conditional && !forms.len().is_multiple_of(2)
29}
30
31pub struct Parser {
32 lexer: Lexer,
33 peeked: Option<(Token, Span)>,
34 discarded: Vec<Form>,
35}
36
37impl Parser {
38 pub fn new(source: String, file: String) -> Self {
39 Self {
40 lexer: Lexer::new(source, file),
41 peeked: None,
42 discarded: Vec::new(),
43 }
44 }
45
46 pub fn parse_one(&mut self) -> CljxResult<Option<Form>> {
50 loop {
51 if matches!(self.peek_tok()?, Token::Eof) {
52 return Ok(None);
53 }
54 if let Some(form) = self.parse_raw()? {
55 return Ok(Some(form)); }
57 }
58 }
59
60 pub fn parse_all(&mut self) -> CljxResult<Vec<Form>> {
62 let mut forms = Vec::new();
63 while let Some(form) = self.parse_one()? {
64 forms.push(form);
65 }
66 Ok(forms)
67 }
68
69 pub fn take_discarded_forms(&mut self) -> Vec<Form> {
75 std::mem::take(&mut self.discarded)
76 }
77
78 fn fill(&mut self) -> CljxResult<()> {
82 if self.peeked.is_none() {
83 let pair = self.lexer.next_token()?;
84 self.peeked = Some(pair);
85 }
86 Ok(())
87 }
88
89 fn bump(&mut self) -> CljxResult<(Token, Span)> {
91 self.fill()?;
92 Ok(self.peeked.take().unwrap())
93 }
94
95 fn peek_tok(&mut self) -> CljxResult<Token> {
97 self.fill()?;
98 Ok(self.peeked.as_ref().unwrap().0.clone())
99 }
100
101 fn peek_span(&mut self) -> CljxResult<Span> {
103 self.fill()?;
104 Ok(self.peeked.as_ref().unwrap().1.clone())
105 }
106
107 fn make_error(&self, msg: impl Into<String>, span: Span) -> CljxError {
110 CljxError::ReadError {
111 message: msg.into(),
112 span: Some(miette::SourceSpan::from(span)),
113 src: NamedSource::new(
114 (**self.lexer.file()).clone(),
115 (**self.lexer.source()).clone(),
116 ),
117 }
118 }
119
120 fn merged_span(&self, start: &Span, end: &Span) -> Span {
123 Span::new(
124 Arc::clone(&start.file),
125 start.start,
126 end.end,
127 start.line,
128 start.col,
129 )
130 }
131
132 fn parse_raw(&mut self) -> CljxResult<Option<Form>> {
137 let tok = self.peek_tok()?;
138 let span = self.peek_span()?;
139
140 match tok {
141 Token::Eof => Ok(None),
142
143 Token::RParen | Token::RBracket | Token::RBrace => {
145 self.bump()?;
146 Err(self.make_error("unexpected closing delimiter", span))
147 }
148
149 Token::Nil => {
151 self.bump()?;
152 Ok(Some(Form::new(FormKind::Nil, span)))
153 }
154 Token::Bool(b) => {
155 self.bump()?;
156 Ok(Some(Form::new(FormKind::Bool(b), span)))
157 }
158 Token::Int(n) => {
159 self.bump()?;
160 Ok(Some(Form::new(FormKind::Int(n), span)))
161 }
162 Token::BigInt(s) => {
163 self.bump()?;
164 Ok(Some(Form::new(FormKind::BigInt(s), span)))
165 }
166 Token::Float(f) => {
167 self.bump()?;
168 Ok(Some(Form::new(FormKind::Float(f), span)))
169 }
170 Token::BigDecimal(s) => {
171 self.bump()?;
172 Ok(Some(Form::new(FormKind::BigDecimal(s), span)))
173 }
174 Token::Ratio(s) => {
175 self.bump()?;
176 Ok(Some(Form::new(FormKind::Ratio(s), span)))
177 }
178 Token::Char(c) => {
179 self.bump()?;
180 Ok(Some(Form::new(FormKind::Char(c), span)))
181 }
182 Token::Str(s) => {
183 self.bump()?;
184 Ok(Some(Form::new(FormKind::Str(s), span)))
185 }
186 Token::Regex(s) => {
187 self.bump()?;
188 Ok(Some(Form::new(FormKind::Regex(s), span)))
189 }
190 Token::Symbolic(s) => {
191 self.bump()?;
192 let val = match s.as_str() {
193 "Inf" => f64::INFINITY,
194 "-Inf" => f64::NEG_INFINITY,
195 "NaN" => f64::NAN,
196 _ => unreachable!("lexer guarantees only Inf/-Inf/NaN"),
197 };
198 Ok(Some(Form::new(FormKind::Symbolic(val), span)))
199 }
200
201 Token::Symbol(s) => {
203 self.bump()?;
204 Ok(Some(Form::new(FormKind::Symbol(s), span)))
205 }
206 Token::Keyword(s) => {
207 self.bump()?;
208 Ok(Some(Form::new(FormKind::Keyword(s), span)))
209 }
210 Token::AutoKeyword(s) => {
211 self.bump()?;
212 Ok(Some(Form::new(FormKind::AutoKeyword(s), span)))
213 }
214
215 Token::LParen => {
217 self.bump()?;
218 let (forms, close) = self.parse_seq_forms(Token::RParen, span.clone(), "list")?;
219 Ok(Some(Form::new(
220 FormKind::List(forms),
221 self.merged_span(&span, &close),
222 )))
223 }
224 Token::LBracket => {
225 self.bump()?;
226 let (forms, close) =
227 self.parse_seq_forms(Token::RBracket, span.clone(), "vector")?;
228 Ok(Some(Form::new(
229 FormKind::Vector(forms),
230 self.merged_span(&span, &close),
231 )))
232 }
233 Token::LBrace => {
234 self.bump()?;
235 let (forms, close) = self.parse_seq_forms(Token::RBrace, span.clone(), "map")?;
236 if map_arity_is_statically_odd(&forms) {
237 return Err(
238 self.make_error("map literal must have an even number of forms", span)
239 );
240 }
241 Ok(Some(Form::new(
242 FormKind::Map(forms),
243 self.merged_span(&span, &close),
244 )))
245 }
246 Token::NamespacedMap(ns) => {
247 self.bump()?;
248 let open = self.peek_span()?;
251 self.bump()?;
252 let (forms, close) =
253 self.parse_seq_forms(Token::RBrace, open.clone(), "namespaced map")?;
254 if !forms.len().is_multiple_of(2) {
255 return Err(
256 self.make_error("map literal must have an even number of forms", span)
257 );
258 }
259 Ok(Some(Form::new(
260 FormKind::Map(namespaced_map::qualify_keys(&ns, forms)),
261 self.merged_span(&span, &close),
262 )))
263 }
264 Token::HashSet => {
265 self.bump()?;
266 let (forms, close) = self.parse_seq_forms(Token::RBrace, span.clone(), "set")?;
267 Ok(Some(Form::new(
268 FormKind::Set(forms),
269 self.merged_span(&span, &close),
270 )))
271 }
272 Token::HashFn => {
273 self.bump()?;
274 let (forms, close) =
275 self.parse_seq_forms(Token::RParen, span.clone(), "anonymous function")?;
276 Ok(Some(Form::new(
277 FormKind::AnonFn(forms),
278 self.merged_span(&span, &close),
279 )))
280 }
281
282 Token::Quote => {
284 self.bump()?;
285 let inner = self.require_form(span.clone(), "quoted form")?;
286 let end = inner.span.clone();
287 Ok(Some(Form::new(
288 FormKind::Quote(Box::new(inner)),
289 self.merged_span(&span, &end),
290 )))
291 }
292 Token::SyntaxQuote => {
293 self.bump()?;
294 let inner = self.require_form(span.clone(), "syntax-quoted form")?;
295 let end = inner.span.clone();
296 Ok(Some(Form::new(
297 FormKind::SyntaxQuote(Box::new(inner)),
298 self.merged_span(&span, &end),
299 )))
300 }
301 Token::Unquote => {
302 self.bump()?;
303 let inner = self.require_form(span.clone(), "unquoted form")?;
304 let end = inner.span.clone();
305 Ok(Some(Form::new(
306 FormKind::Unquote(Box::new(inner)),
307 self.merged_span(&span, &end),
308 )))
309 }
310 Token::UnquoteSplice => {
311 self.bump()?;
312 let inner = self.require_form(span.clone(), "unquote-spliced form")?;
313 let end = inner.span.clone();
314 Ok(Some(Form::new(
315 FormKind::UnquoteSplice(Box::new(inner)),
316 self.merged_span(&span, &end),
317 )))
318 }
319 Token::Deref => {
320 self.bump()?;
321 let inner = self.require_form(span.clone(), "deref form")?;
322 let end = inner.span.clone();
323 Ok(Some(Form::new(
324 FormKind::Deref(Box::new(inner)),
325 self.merged_span(&span, &end),
326 )))
327 }
328 Token::HashVar => {
329 self.bump()?;
330 let inner = self.require_form(span.clone(), "var form")?;
331 let end = inner.span.clone();
332 Ok(Some(Form::new(
333 FormKind::Var(Box::new(inner)),
334 self.merged_span(&span, &end),
335 )))
336 }
337 Token::Meta => {
338 self.bump()?;
339 let meta = self.require_form(span.clone(), "meta form")?;
340 let target = self.require_form(span.clone(), "annotated form")?;
341 let end = target.span.clone();
342 Ok(Some(Form::new(
343 FormKind::Meta(Box::new(meta), Box::new(target)),
344 self.merged_span(&span, &end),
345 )))
346 }
347
348 Token::HashDiscard => {
350 self.bump()?;
351 if matches!(self.peek_tok()?, Token::Eof) {
352 return Err(self.make_error("unexpected end of file after #_", span));
353 }
354 let discarded = self.require_form(span.clone(), "discarded form")?;
358 self.discarded.push(discarded);
359 Ok(None)
360 }
361
362 Token::ReaderCond => {
364 self.bump()?;
365 let form = self.parse_reader_cond(false, span)?;
366 Ok(Some(form))
367 }
368 Token::ReaderCondSplice => {
369 self.bump()?;
370 let form = self.parse_reader_cond(true, span)?;
371 Ok(Some(form))
372 }
373
374 Token::TaggedLiteral(tag) => {
376 self.bump()?;
377 let inner = self.require_form(span.clone(), "tagged literal value")?;
378 let end = inner.span.clone();
379 Ok(Some(Form::new(
380 FormKind::TaggedLiteral(tag, Box::new(inner)),
381 self.merged_span(&span, &end),
382 )))
383 }
384 }
385 }
386
387 fn parse_seq_forms(
391 &mut self,
392 closing: Token,
393 open_span: Span,
394 name: &str,
395 ) -> CljxResult<(Vec<Form>, Span)> {
396 let mut forms = Vec::new();
397 loop {
398 let tok = self.peek_tok()?;
399 if tok == Token::Eof {
400 return Err(self.make_error(format!("unclosed {name}"), open_span));
401 }
402 if tok == closing {
403 let (_, close_span) = self.bump()?;
404 return Ok((forms, close_span));
405 }
406 if let Some(form) = self.parse_raw()? {
407 forms.push(form); }
409 }
410 }
411
412 fn require_form(&mut self, macro_span: Span, what: &str) -> CljxResult<Form> {
415 loop {
416 if matches!(self.peek_tok()?, Token::Eof) {
417 return Err(self.make_error(
418 format!("unexpected end of file; expected {what}"),
419 macro_span,
420 ));
421 }
422 if let Some(form) = self.parse_raw()? {
423 return Ok(form); }
425 }
426 }
427
428 fn parse_reader_cond(&mut self, splicing: bool, start: Span) -> CljxResult<Form> {
431 let next = self.peek_tok()?;
432 if next != Token::LParen {
433 let span = self.peek_span()?;
434 return Err(self.make_error(
435 "reader conditional requires `(` immediately after `#?`",
436 span,
437 ));
438 }
439 let (_, open_span) = self.bump()?; let (clauses, close_span) =
441 self.parse_seq_forms(Token::RParen, open_span.clone(), "reader conditional")?;
442 if clauses.len() % 2 != 0 {
443 return Err(self.make_error(
444 "reader conditional must have an even number of clauses",
445 open_span,
446 ));
447 }
448 Ok(Form::new(
449 FormKind::ReaderCond { splicing, clauses },
450 self.merged_span(&start, &close_span),
451 ))
452 }
453}
454
455impl Iterator for Parser {
458 type Item = CljxResult<Form>;
459
460 fn next(&mut self) -> Option<Self::Item> {
461 match self.parse_one() {
462 Ok(Some(form)) => Some(Ok(form)),
463 Ok(None) => None,
464 Err(e) => Some(Err(e)),
465 }
466 }
467}
468
469#[cfg(test)]
472mod tests {
473 use std::sync::Arc;
474
475 use cljrs_types::{error::CljxError, span::Span};
476
477 use super::*;
478
479 fn dummy_span() -> Span {
482 Span::new(Arc::new("<test>".to_string()), 0, 0, 1, 1)
483 }
484
485 fn f(kind: FormKind) -> Form {
487 Form::new(kind, dummy_span())
488 }
489
490 fn parse_all(src: &str) -> Vec<Form> {
491 Parser::new(src.to_string(), "<test>".to_string())
492 .parse_all()
493 .unwrap_or_else(|e| panic!("parse error: {e}"))
494 }
495
496 fn parse1(src: &str) -> Form {
497 Parser::new(src.to_string(), "<test>".to_string())
498 .parse_one()
499 .unwrap_or_else(|e| panic!("parse error: {e}"))
500 .expect("expected a form but got EOF")
501 }
502
503 fn parse_err(src: &str) -> String {
504 let mut p = Parser::new(src.to_string(), "<test>".to_string());
505 match p.parse_all() {
506 Err(CljxError::ReadError { message, .. }) => message,
507 Err(e) => panic!("unexpected error type: {e:?}"),
508 Ok(forms) => panic!("expected a parse error but got: {forms:?}"),
509 }
510 }
511
512 #[test]
515 fn test_nil() {
516 assert_eq!(parse1("nil").kind, FormKind::Nil);
517 }
518
519 #[test]
520 fn test_bool() {
521 assert_eq!(parse1("true").kind, FormKind::Bool(true));
522 assert_eq!(parse1("false").kind, FormKind::Bool(false));
523 }
524
525 #[test]
526 fn test_int() {
527 assert_eq!(parse1("42").kind, FormKind::Int(42));
528 assert_eq!(parse1("-7").kind, FormKind::Int(-7));
529 }
530
531 #[test]
532 fn test_bigint() {
533 assert_eq!(parse1("42N").kind, FormKind::BigInt("42".to_string()));
534 }
535
536 #[test]
537 #[allow(clippy::approx_constant)]
538 fn test_float() {
539 assert_eq!(parse1("3.14").kind, FormKind::Float(3.14));
540 assert_eq!(parse1("1e10").kind, FormKind::Float(1e10));
541 }
542
543 #[test]
544 fn test_bigdecimal() {
545 assert_eq!(
546 parse1("3.14M").kind,
547 FormKind::BigDecimal("3.14".to_string())
548 );
549 }
550
551 #[test]
552 fn test_ratio() {
553 assert_eq!(parse1("3/4").kind, FormKind::Ratio("3/4".to_string()));
554 assert_eq!(parse1("-1/2").kind, FormKind::Ratio("-1/2".to_string()));
555 }
556
557 #[test]
558 fn test_char() {
559 assert_eq!(parse1("\\a").kind, FormKind::Char('a'));
560 assert_eq!(parse1("\\newline").kind, FormKind::Char('\n'));
561 }
562
563 #[test]
564 fn test_str() {
565 assert_eq!(parse1("\"hello\"").kind, FormKind::Str("hello".to_string()));
566 }
567
568 #[test]
569 fn test_regex() {
570 assert_eq!(
571 parse1("#\"[a-z]+\"").kind,
572 FormKind::Regex("[a-z]+".to_string())
573 );
574 }
575
576 #[test]
577 fn test_symbolic() {
578 assert!(matches!(
579 parse1("##Inf").kind,
580 FormKind::Symbolic(f) if f == f64::INFINITY
581 ));
582 assert!(matches!(
583 parse1("##-Inf").kind,
584 FormKind::Symbolic(f) if f == f64::NEG_INFINITY
585 ));
586 assert!(matches!(
588 parse1("##NaN").kind,
589 FormKind::Symbolic(f) if f.is_nan()
590 ));
591 }
592
593 #[test]
594 fn test_symbol() {
595 assert_eq!(parse1("foo").kind, FormKind::Symbol("foo".to_string()));
596 }
597
598 #[test]
599 fn test_keyword() {
600 assert_eq!(parse1(":foo").kind, FormKind::Keyword("foo".to_string()));
601 }
602
603 #[test]
604 fn test_auto_keyword() {
605 assert_eq!(
606 parse1("::foo").kind,
607 FormKind::AutoKeyword("foo".to_string())
608 );
609 }
610
611 #[test]
614 fn test_empty_list() {
615 assert_eq!(parse1("()").kind, FormKind::List(vec![]));
616 }
617
618 #[test]
619 fn test_list() {
620 assert_eq!(
621 parse1("(1 2 3)").kind,
622 FormKind::List(vec![
623 f(FormKind::Int(1)),
624 f(FormKind::Int(2)),
625 f(FormKind::Int(3)),
626 ])
627 );
628 }
629
630 #[test]
631 fn test_vector() {
632 assert_eq!(
633 parse1("[1 2]").kind,
634 FormKind::Vector(vec![f(FormKind::Int(1)), f(FormKind::Int(2))])
635 );
636 }
637
638 #[test]
639 fn test_map() {
640 assert_eq!(
641 parse1("{:a 1}").kind,
642 FormKind::Map(vec![
643 f(FormKind::Keyword("a".to_string())),
644 f(FormKind::Int(1)),
645 ])
646 );
647 }
648
649 #[test]
650 fn test_namespaced_map_literal_ns() {
651 assert_eq!(
652 parse1("#:adt{:a 1 :b 2}").kind,
653 FormKind::Map(vec![
654 f(FormKind::Keyword("adt/a".to_string())),
655 f(FormKind::Int(1)),
656 f(FormKind::Keyword("adt/b".to_string())),
657 f(FormKind::Int(2)),
658 ])
659 );
660 }
661
662 #[test]
663 fn test_namespaced_map_leaves_values_and_explicit_keys_alone() {
664 assert_eq!(
665 parse1("#:adt{:a :b other/c 1 :_/d 2}").kind,
666 FormKind::Map(vec![
667 f(FormKind::Keyword("adt/a".to_string())),
668 f(FormKind::Keyword("b".to_string())),
670 f(FormKind::Symbol("other/c".to_string())),
672 f(FormKind::Int(1)),
673 f(FormKind::Keyword("d".to_string())),
675 f(FormKind::Int(2)),
676 ])
677 );
678 }
679
680 #[test]
681 fn test_namespaced_map_auto_resolved_lowers_to_auto_keyword() {
682 assert_eq!(
683 parse1("#::{:a 1}").kind,
684 FormKind::Map(vec![
685 f(FormKind::AutoKeyword("a".to_string())),
686 f(FormKind::Int(1)),
687 ])
688 );
689 assert_eq!(
690 parse1("#::al{:a 1}").kind,
691 FormKind::Map(vec![
692 f(FormKind::AutoKeyword("al/a".to_string())),
693 f(FormKind::Int(1)),
694 ])
695 );
696 }
697
698 #[test]
699 fn test_namespaced_map_nests() {
700 assert_eq!(
701 parse1("#:a{:x #:b{:y 1}}").kind,
702 FormKind::Map(vec![
703 f(FormKind::Keyword("a/x".to_string())),
704 f(FormKind::Map(vec![
705 f(FormKind::Keyword("b/y".to_string())),
706 f(FormKind::Int(1)),
707 ])),
708 ])
709 );
710 }
711
712 #[test]
713 fn test_namespaced_map_odd_form_count_is_an_error() {
714 let err = parse_err("#:a{:x}");
715 assert!(err.contains("even number of forms"), "{err}");
716 }
717
718 #[test]
719 fn test_set() {
720 assert_eq!(
721 parse1("#{1 2}").kind,
722 FormKind::Set(vec![f(FormKind::Int(1)), f(FormKind::Int(2))])
723 );
724 }
725
726 #[test]
729 fn test_nested() {
730 assert_eq!(
731 parse1("(+ [1 2] {:a 3})").kind,
732 FormKind::List(vec![
733 f(FormKind::Symbol("+".to_string())),
734 f(FormKind::Vector(vec![
735 f(FormKind::Int(1)),
736 f(FormKind::Int(2)),
737 ])),
738 f(FormKind::Map(vec![
739 f(FormKind::Keyword("a".to_string())),
740 f(FormKind::Int(3)),
741 ])),
742 ])
743 );
744 }
745
746 #[test]
749 fn test_quote() {
750 assert_eq!(
751 parse1("'foo").kind,
752 FormKind::Quote(Box::new(f(FormKind::Symbol("foo".to_string()))))
753 );
754 }
755
756 #[test]
757 fn test_syntax_quote() {
758 assert_eq!(
759 parse1("`foo").kind,
760 FormKind::SyntaxQuote(Box::new(f(FormKind::Symbol("foo".to_string()))))
761 );
762 }
763
764 #[test]
765 fn test_unquote() {
766 assert_eq!(
767 parse1("~foo").kind,
768 FormKind::Unquote(Box::new(f(FormKind::Symbol("foo".to_string()))))
769 );
770 }
771
772 #[test]
773 fn test_unquote_splice() {
774 assert_eq!(
775 parse1("~@foo").kind,
776 FormKind::UnquoteSplice(Box::new(f(FormKind::Symbol("foo".to_string()))))
777 );
778 }
779
780 #[test]
781 fn test_deref() {
782 assert_eq!(
783 parse1("@foo").kind,
784 FormKind::Deref(Box::new(f(FormKind::Symbol("foo".to_string()))))
785 );
786 }
787
788 #[test]
789 fn test_var() {
790 assert_eq!(
791 parse1("#'foo").kind,
792 FormKind::Var(Box::new(f(FormKind::Symbol("foo".to_string()))))
793 );
794 }
795
796 #[test]
799 fn test_meta_map() {
800 assert_eq!(
801 parse1("^{:a 1} foo").kind,
802 FormKind::Meta(
803 Box::new(f(FormKind::Map(vec![
804 f(FormKind::Keyword("a".to_string())),
805 f(FormKind::Int(1)),
806 ]))),
807 Box::new(f(FormKind::Symbol("foo".to_string()))),
808 )
809 );
810 }
811
812 #[test]
813 fn test_meta_keyword() {
814 assert_eq!(
815 parse1("^:kw foo").kind,
816 FormKind::Meta(
817 Box::new(f(FormKind::Keyword("kw".to_string()))),
818 Box::new(f(FormKind::Symbol("foo".to_string()))),
819 )
820 );
821 }
822
823 #[test]
824 fn test_meta_symbol() {
825 assert_eq!(
826 parse1("^Sym foo").kind,
827 FormKind::Meta(
828 Box::new(f(FormKind::Symbol("Sym".to_string()))),
829 Box::new(f(FormKind::Symbol("foo".to_string()))),
830 )
831 );
832 }
833
834 #[test]
837 fn test_anon_fn() {
838 assert_eq!(
839 parse1("#(+ % 1)").kind,
840 FormKind::AnonFn(vec![
841 f(FormKind::Symbol("+".to_string())),
842 f(FormKind::Symbol("%".to_string())),
843 f(FormKind::Int(1)),
844 ])
845 );
846 }
847
848 #[test]
851 fn test_discard_simple() {
852 let forms = parse_all("#_foo bar");
853 assert_eq!(forms.len(), 1);
854 assert_eq!(forms[0].kind, FormKind::Symbol("bar".to_string()));
855 }
856
857 #[test]
858 fn test_discard_in_vector() {
859 assert_eq!(
860 parse1("[1 #_2 3]").kind,
861 FormKind::Vector(vec![f(FormKind::Int(1)), f(FormKind::Int(3))])
862 );
863 }
864
865 #[test]
866 fn test_discard_chained() {
867 let forms = parse_all("#_ #_ 1 2 3");
869 assert_eq!(forms.len(), 1);
870 assert_eq!(forms[0].kind, FormKind::Int(3));
871 }
872
873 #[test]
876 fn test_reader_cond() {
877 assert_eq!(
878 parse1("#?(:rust 1 :clj 2)").kind,
879 FormKind::ReaderCond {
880 splicing: false,
881 clauses: vec![
882 f(FormKind::Keyword("rust".to_string())),
883 f(FormKind::Int(1)),
884 f(FormKind::Keyword("clj".to_string())),
885 f(FormKind::Int(2)),
886 ],
887 }
888 );
889 }
890
891 #[test]
892 fn test_reader_cond_splice() {
893 assert_eq!(
894 parse1("#?@(:rust [1 2])").kind,
895 FormKind::ReaderCond {
896 splicing: true,
897 clauses: vec![
898 f(FormKind::Keyword("rust".to_string())),
899 f(FormKind::Vector(vec![
900 f(FormKind::Int(1)),
901 f(FormKind::Int(2)),
902 ])),
903 ],
904 }
905 );
906 }
907
908 #[test]
911 fn test_tagged_literal() {
912 assert_eq!(
913 parse1("#inst \"2024-01-01\"").kind,
914 FormKind::TaggedLiteral(
915 "inst".to_string(),
916 Box::new(f(FormKind::Str("2024-01-01".to_string()))),
917 )
918 );
919 }
920
921 #[test]
924 fn test_span_col_offset() {
925 let form = parse1(" 42");
926 assert_eq!(form.span.start, 2);
927 assert_eq!(form.span.col, 3);
928 }
929
930 #[test]
931 fn test_span_multiline() {
932 let forms = parse_all("a\nb");
933 assert_eq!(forms[0].span.line, 1);
934 assert_eq!(forms[1].span.line, 2);
935 }
936
937 #[test]
940 fn test_parse_all_multiple() {
941 let forms = parse_all("1 2 3");
942 assert_eq!(forms.len(), 3);
943 assert_eq!(forms[0].kind, FormKind::Int(1));
944 assert_eq!(forms[1].kind, FormKind::Int(2));
945 assert_eq!(forms[2].kind, FormKind::Int(3));
946 }
947
948 #[test]
951 fn test_err_unclosed_list() {
952 let msg = parse_err("(1 2");
953 assert!(msg.contains("unclosed") || msg.contains("list"), "{msg}");
954 }
955
956 #[test]
957 fn test_err_unexpected_close() {
958 let msg = parse_err(")");
959 assert!(msg.contains("unexpected"), "{msg}");
960 }
961
962 #[test]
963 fn test_err_odd_map() {
964 let msg = parse_err("{:a}");
965 assert!(msg.contains("even") || msg.contains("map"), "{msg}");
966 }
967
968 #[test]
969 fn test_map_with_splice_defers_parity_check() {
970 let mut p = Parser::new(
971 "{:a 1 #?@(:rust [:b 2]) :c 3}".to_string(),
972 "<test>".to_string(),
973 );
974 let form = p.parse_one().unwrap().unwrap();
975 assert!(matches!(form.kind, FormKind::Map(_)));
976 }
977
978 #[test]
979 fn test_map_with_non_splicing_conditional_defers_parity_check() {
980 for src in ["{#?(:clj :a)}", "{:a #?(:rust 1 :clj 2) :b 2}"] {
984 let mut p = Parser::new(src.to_string(), "<test>".to_string());
985 let form = p
986 .parse_one()
987 .unwrap_or_else(|e| panic!("{src} rejected at read time: {e}"))
988 .unwrap();
989 assert!(matches!(form.kind, FormKind::Map(_)), "{src}");
990 }
991 }
992
993 #[test]
994 fn test_map_odd_without_splice_still_errors() {
995 let msg = parse_err("{:a 1 :b}");
996 assert!(msg.contains("even") || msg.contains("map"), "{msg}");
997 }
998
999 #[test]
1000 fn test_err_reader_cond_non_list() {
1001 let msg = parse_err("#?[1 2]");
1003 assert!(
1004 msg.contains('(') || msg.contains("reader conditional"),
1005 "{msg}"
1006 );
1007 }
1008
1009 #[test]
1010 fn test_err_odd_reader_cond_clauses() {
1011 let msg = parse_err("#?(:cljx)");
1012 assert!(
1013 msg.contains("even") || msg.contains("reader conditional"),
1014 "{msg}"
1015 );
1016 }
1017}