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