1use std::collections::BTreeMap;
2use std::rc::Rc;
3
4use sema_core::{resolve, SemaError, Span, SpanMap, Value, ValueView};
5
6use crate::lexer::{tokenize, FStringPart, SpannedToken, Token};
7
8struct Parser {
9 tokens: Vec<SpannedToken>,
10 pos: usize,
11 span_map: SpanMap,
12}
13
14impl Parser {
15 fn new(tokens: Vec<SpannedToken>) -> Self {
16 Parser {
17 tokens,
18 pos: 0,
19 span_map: SpanMap::new(),
20 }
21 }
22
23 fn peek(&self) -> Option<&Token> {
24 let mut pos = self.pos;
25 while let Some(t) = self.tokens.get(pos) {
26 match &t.token {
27 Token::Comment(_) | Token::Newline => pos += 1,
28 _ => return Some(&t.token),
29 }
30 }
31 None
32 }
33
34 fn span(&self) -> Span {
35 let mut pos = self.pos;
36 while let Some(t) = self.tokens.get(pos) {
37 match &t.token {
38 Token::Comment(_) | Token::Newline => pos += 1,
39 _ => return t.span,
40 }
41 }
42 Span::point(0, 0)
43 }
44
45 fn skip_trivia(&mut self) {
46 while let Some(t) = self.tokens.get(self.pos) {
47 match &t.token {
48 Token::Comment(_) | Token::Newline => self.pos += 1,
49 _ => break,
50 }
51 }
52 }
53
54 fn advance(&mut self) -> Option<&SpannedToken> {
55 self.skip_trivia();
56 let tok = self.tokens.get(self.pos);
57 if tok.is_some() {
58 self.pos += 1;
59 }
60 tok
61 }
62
63 fn expect(&mut self, expected: &Token) -> Result<(), SemaError> {
64 let span = self.span();
65 match self.advance() {
66 Some(t) if &t.token == expected => Ok(()),
67 Some(t) => Err(SemaError::Reader {
68 message: format!(
69 "expected `{}`, got `{}`",
70 token_display(expected),
71 token_display(&t.token)
72 ),
73 span,
74 }),
75 None => Err(SemaError::Reader {
76 message: format!("expected `{}`, got end of input", token_display(expected)),
77 span,
78 }),
79 }
80 }
81
82 fn parse_expr(&mut self) -> Result<Value, SemaError> {
83 let span = self.span();
84 match self.peek() {
85 None => Err(SemaError::Reader {
86 message: "unexpected end of input".to_string(),
87 span,
88 }),
89 Some(Token::LParen) => self.parse_list(),
90 Some(Token::LBracket) => self.parse_vector(),
91 Some(Token::LBrace) => self.parse_map(),
92 Some(Token::Quote) => {
93 self.advance();
94 let inner = self.parse_expr().map_err(|_| {
95 SemaError::Reader {
96 message: "quote (') requires an expression after it".to_string(),
97 span,
98 }
99 .with_hint("e.g. '(1 2 3) or 'foo")
100 })?;
101 self.make_list_with_span(vec![Value::symbol("quote"), inner], span)
102 }
103 Some(Token::Quasiquote) => {
104 self.advance();
105 let inner = self.parse_expr().map_err(|_| {
106 SemaError::Reader {
107 message: "quasiquote (`) requires an expression after it".to_string(),
108 span,
109 }
110 .with_hint("e.g. `(list ,x)")
111 })?;
112 self.make_list_with_span(vec![Value::symbol("quasiquote"), inner], span)
113 }
114 Some(Token::Unquote) => {
115 self.advance();
116 let inner = self.parse_expr().map_err(|_| {
117 SemaError::Reader {
118 message: "unquote (,) requires an expression after it".to_string(),
119 span,
120 }
121 .with_hint("use inside quasiquote, e.g. `(list ,x)")
122 })?;
123 self.make_list_with_span(vec![Value::symbol("unquote"), inner], span)
124 }
125 Some(Token::UnquoteSplice) => {
126 self.advance();
127 let inner = self.parse_expr().map_err(|_| {
128 SemaError::Reader {
129 message: "unquote-splicing (,@) requires an expression after it"
130 .to_string(),
131 span,
132 }
133 .with_hint("use inside quasiquote, e.g. `(list ,@xs)")
134 })?;
135 self.make_list_with_span(vec![Value::symbol("unquote-splicing"), inner], span)
136 }
137 Some(Token::BytevectorStart) => self.parse_bytevector(),
138 Some(Token::ShortLambdaStart) => self.parse_short_lambda(),
139 Some(_) => self.parse_atom(),
140 }
141 }
142
143 fn make_list_with_span(&mut self, items: Vec<Value>, span: Span) -> Result<Value, SemaError> {
144 let rc = Rc::new(items);
145 let ptr = Rc::as_ptr(&rc) as usize;
146 self.span_map.insert(ptr, span);
147 Ok(Value::list_from_rc(rc))
148 }
149
150 fn prev_span(&self) -> Span {
152 if self.pos > 0 {
153 self.tokens[self.pos - 1].span
154 } else {
155 Span::point(0, 0)
156 }
157 }
158
159 fn parse_list(&mut self) -> Result<Value, SemaError> {
160 let open_span = self.span();
161 self.expect(&Token::LParen)?;
162 let mut items = Vec::new();
163 while self.peek() != Some(&Token::RParen) {
164 if self.peek().is_none() {
165 return Err(SemaError::Reader {
166 message: "unterminated list".to_string(),
167 span: open_span,
168 }
169 .with_hint("add a closing `)`"));
170 }
171 if self.peek() == Some(&Token::RBracket) {
172 return Err(SemaError::Reader {
173 message: "mismatched bracket: expected `)` to close `(`, found `]`".to_string(),
174 span: self.span(),
175 }
176 .with_hint("this list was opened with `(` — close it with `)`"));
177 }
178 if self.peek() == Some(&Token::RBrace) {
179 return Err(SemaError::Reader {
180 message: "mismatched bracket: expected `)` to close `(`, found `}`".to_string(),
181 span: self.span(),
182 }
183 .with_hint("this list was opened with `(` — close it with `)`"));
184 }
185 if self.peek() == Some(&Token::Dot) {
187 self.advance(); let cdr = self.parse_expr()?;
189 self.expect(&Token::RParen)?;
190 let close = self.prev_span();
191 items.push(Value::symbol("."));
192 items.push(cdr);
193 return self.make_list_with_span(items, open_span.to(&close));
194 }
195 items.push(self.parse_expr()?);
196 }
197 self.expect(&Token::RParen)?;
198 let close = self.prev_span();
199 self.make_list_with_span(items, open_span.to(&close))
200 }
201
202 fn parse_vector(&mut self) -> Result<Value, SemaError> {
203 let open_span = self.span();
204 self.expect(&Token::LBracket)?;
205 let mut items = Vec::new();
206 while self.peek() != Some(&Token::RBracket) {
207 if self.peek().is_none() {
208 return Err(SemaError::Reader {
209 message: "unterminated vector".to_string(),
210 span: open_span,
211 }
212 .with_hint("add a closing `]`"));
213 }
214 if self.peek() == Some(&Token::RParen) {
215 return Err(SemaError::Reader {
216 message: "mismatched bracket: expected `]` to close `[`, found `)`".to_string(),
217 span: self.span(),
218 }
219 .with_hint("this vector was opened with `[` — close it with `]`"));
220 }
221 if self.peek() == Some(&Token::RBrace) {
222 return Err(SemaError::Reader {
223 message: "mismatched bracket: expected `]` to close `[`, found `}`".to_string(),
224 span: self.span(),
225 }
226 .with_hint("this vector was opened with `[` — close it with `]`"));
227 }
228 items.push(self.parse_expr()?);
229 }
230 self.expect(&Token::RBracket)?;
231 let close = self.prev_span();
232 let rc = Rc::new(items);
233 let ptr = Rc::as_ptr(&rc) as usize;
234 self.span_map.insert(ptr, open_span.to(&close));
235 Ok(Value::vector_from_rc(rc))
236 }
237
238 fn parse_map(&mut self) -> Result<Value, SemaError> {
239 let open_span = self.span();
240 self.expect(&Token::LBrace)?;
241 let mut map = BTreeMap::new();
242 while self.peek() != Some(&Token::RBrace) {
243 if self.peek().is_none() {
244 return Err(SemaError::Reader {
245 message: "unterminated map".to_string(),
246 span: open_span,
247 }
248 .with_hint("add a closing `}`"));
249 }
250 if self.peek() == Some(&Token::RParen) {
251 return Err(SemaError::Reader {
252 message: "mismatched bracket: expected `}` to close `{`, found `)`".to_string(),
253 span: self.span(),
254 }
255 .with_hint("this map was opened with `{` — close it with `}`"));
256 }
257 if self.peek() == Some(&Token::RBracket) {
258 return Err(SemaError::Reader {
259 message: "mismatched bracket: expected `}` to close `{`, found `]`".to_string(),
260 span: self.span(),
261 }
262 .with_hint("this map was opened with `{` — close it with `}`"));
263 }
264 let key = self.parse_expr()?;
265 if self.peek() == Some(&Token::RBrace) || self.peek().is_none() {
266 return Err(SemaError::Reader {
267 message: "map literal must have even number of forms".to_string(),
268 span: self.span(),
269 });
270 }
271 let val = self.parse_expr()?;
272 map.insert(key, val);
273 }
274 self.expect(&Token::RBrace)?;
275 Ok(Value::map(map))
276 }
277
278 fn parse_bytevector(&mut self) -> Result<Value, SemaError> {
279 let open_span = self.span();
280 self.advance(); let mut bytes = Vec::new();
282 while self.peek() != Some(&Token::RParen) {
283 if self.peek().is_none() {
284 return Err(SemaError::Reader {
285 message: "unterminated bytevector".to_string(),
286 span: open_span,
287 }
288 .with_hint("add a closing `)`"));
289 }
290 let span = self.span();
291 match self.peek() {
292 Some(Token::Int(n)) => {
293 let n = *n;
294 self.advance();
295 if !(0..=255).contains(&n) {
296 return Err(SemaError::Reader {
297 message: format!("#u8(...): byte value {n} out of range 0..255"),
298 span,
299 });
300 }
301 bytes.push(n as u8);
302 }
303 _ => {
304 return Err(SemaError::Reader {
305 message: "#u8(...): expected integer byte value".to_string(),
306 span,
307 });
308 }
309 }
310 }
311 self.expect(&Token::RParen)?;
312 Ok(Value::bytevector(bytes))
313 }
314
315 fn parse_short_lambda(&mut self) -> Result<Value, SemaError> {
316 let open_span = self.span();
317 self.advance(); let mut body_items = Vec::new();
319 while self.peek() != Some(&Token::RParen) {
320 if self.peek().is_none() {
321 return Err(SemaError::Reader {
322 message: "unterminated short lambda #(...)".to_string(),
323 span: open_span,
324 }
325 .with_hint("add a closing `)`"));
326 }
327 body_items.push(self.parse_expr()?);
328 }
329 self.expect(&Token::RParen)?;
330
331 let body = Value::list(body_items);
333
334 let mut max_arg: usize = 0;
336 let body = rewrite_percent_args(&body, &mut max_arg);
337
338 let params: Vec<Value> = if max_arg == 0 {
340 vec![]
341 } else {
342 (1..=max_arg)
343 .map(|n| Value::symbol(&format!("%{}", n)))
344 .collect()
345 };
346
347 Ok(Value::list(vec![
348 Value::symbol("lambda"),
349 Value::list(params),
350 body,
351 ]))
352 }
353
354 fn parse_atom(&mut self) -> Result<Value, SemaError> {
355 let span = self.span();
356 match self.advance() {
357 Some(SpannedToken {
358 token: Token::Int(n),
359 ..
360 }) => Ok(Value::int(*n)),
361 Some(SpannedToken {
362 token: Token::Float(f),
363 ..
364 }) => Ok(Value::float(*f)),
365 Some(SpannedToken {
366 token: Token::String(s),
367 ..
368 }) => Ok(Value::string(s)),
369 Some(SpannedToken {
370 token: Token::Regex(s),
371 ..
372 }) => Ok(Value::string(s)),
373 Some(SpannedToken {
374 token: Token::Symbol(s),
375 ..
376 }) => {
377 if s == "nil" {
378 Ok(Value::nil())
379 } else {
380 Ok(Value::symbol(s))
381 }
382 }
383 Some(SpannedToken {
384 token: Token::Keyword(s),
385 ..
386 }) => Ok(Value::keyword(s)),
387 Some(SpannedToken {
388 token: Token::Bool(b),
389 ..
390 }) => Ok(Value::bool(*b)),
391 Some(SpannedToken {
392 token: Token::Char(c),
393 ..
394 }) => Ok(Value::char(*c)),
395 Some(SpannedToken {
396 token: Token::FString(parts),
397 ..
398 }) => {
399 let parts = parts.clone();
400 let mut items = vec![Value::symbol("str")];
401 for part in &parts {
402 match part {
403 FStringPart::Literal(s) => {
404 if !s.is_empty() {
405 items.push(Value::string(s));
406 }
407 }
408 FStringPart::Expr(src) => {
409 let val = read(src)?;
410 items.push(val);
411 }
412 }
413 }
414 Ok(Value::list(items))
415 }
416 Some(t) => {
417 let (name, hint) = match &t.token {
418 Token::RParen => (
419 "unexpected closing `)`",
420 Some("no matching opening parenthesis"),
421 ),
422 Token::RBracket => (
423 "unexpected closing `]`",
424 Some("no matching opening bracket"),
425 ),
426 Token::RBrace => ("unexpected closing `}`", Some("no matching opening brace")),
427 Token::Dot => (
428 "unexpected `.`",
429 Some("dots are used in pair notation, e.g. (a . b)"),
430 ),
431 _ => ("unexpected token", None),
432 };
433 let err = SemaError::Reader {
434 message: name.to_string(),
435 span,
436 };
437 Err(if let Some(h) = hint {
438 err.with_hint(h)
439 } else {
440 err
441 })
442 }
443 None => Err(SemaError::Reader {
444 message: "unexpected end of input".to_string(),
445 span,
446 }),
447 }
448 }
449}
450
451fn token_display(tok: &Token) -> &'static str {
452 match tok {
453 Token::LParen => "(",
454 Token::RParen => ")",
455 Token::LBracket => "[",
456 Token::RBracket => "]",
457 Token::LBrace => "{",
458 Token::RBrace => "}",
459 Token::Quote => "'",
460 Token::Quasiquote => "`",
461 Token::Unquote => ",",
462 Token::UnquoteSplice => ",@",
463 Token::Dot => ".",
464 Token::BytevectorStart => "#u8(",
465 Token::Int(_) => "integer",
466 Token::Float(_) => "float",
467 Token::String(_) => "string",
468 Token::Symbol(_) => "symbol",
469 Token::Keyword(_) => "keyword",
470 Token::Bool(_) => "boolean",
471 Token::Char(_) => "character",
472 Token::FString(_) => "f-string",
473 Token::ShortLambdaStart => "#(",
474 Token::Comment(_) => "comment",
475 Token::Newline => "newline",
476 Token::Regex(_) => "regex",
477 }
478}
479
480fn rewrite_percent_args(expr: &Value, max_arg: &mut usize) -> Value {
484 match expr.view() {
485 ValueView::Symbol(spur) => {
486 let name = resolve(spur);
487 if name == "%" {
488 *max_arg = (*max_arg).max(1);
489 Value::symbol("%1")
490 } else if let Some(rest) = name.strip_prefix('%') {
491 if let Ok(n) = rest.parse::<usize>() {
492 if n > 0 {
493 *max_arg = (*max_arg).max(n);
494 }
495 }
496 expr.clone()
497 } else {
498 expr.clone()
499 }
500 }
501 ValueView::List(items) => {
502 if let Some(first) = items.first() {
504 if let ValueView::Symbol(s) = first.view() {
505 let name = resolve(s);
506 if name == "lambda" || name == "fn" {
507 return expr.clone();
508 }
509 }
510 }
511 let new_items: Vec<Value> = items
512 .iter()
513 .map(|item| rewrite_percent_args(item, max_arg))
514 .collect();
515 Value::list(new_items)
516 }
517 ValueView::Vector(items) => {
518 let new_items: Vec<Value> = items
519 .iter()
520 .map(|item| rewrite_percent_args(item, max_arg))
521 .collect();
522 Value::vector(new_items)
523 }
524 _ => expr.clone(),
525 }
526}
527
528pub fn read(input: &str) -> Result<Value, SemaError> {
530 let tokens = tokenize(input)?;
531 let mut parser = Parser::new(tokens);
532 if parser.peek().is_none() {
533 return Ok(Value::nil());
534 }
535 parser.parse_expr()
536}
537
538pub fn read_many(input: &str) -> Result<Vec<Value>, SemaError> {
540 let tokens = tokenize(input)?;
541 let mut parser = Parser::new(tokens);
542 let mut exprs = Vec::new();
543 while parser.peek().is_some() {
544 exprs.push(parser.parse_expr()?);
545 }
546 Ok(exprs)
547}
548
549pub fn read_many_with_spans(input: &str) -> Result<(Vec<Value>, SpanMap), SemaError> {
551 let tokens = tokenize(input)?;
552 let mut parser = Parser::new(tokens);
553 let mut exprs = Vec::new();
554 while parser.peek().is_some() {
555 exprs.push(parser.parse_expr()?);
556 }
557 Ok((exprs, parser.span_map))
558}
559
560#[cfg(test)]
561mod tests {
562 use super::*;
563
564 #[test]
565 fn test_read_int() {
566 assert_eq!(read("42").unwrap(), Value::int(42));
567 }
568
569 #[test]
570 fn test_read_negative_int() {
571 assert_eq!(read("-7").unwrap(), Value::int(-7));
572 }
573
574 #[test]
575 fn test_read_float() {
576 assert_eq!(read("3.14").unwrap(), Value::float(3.14));
577 }
578
579 #[test]
580 fn test_read_string() {
581 assert_eq!(read("\"hello\"").unwrap(), Value::string("hello"));
582 }
583
584 #[test]
585 fn test_read_symbol() {
586 assert_eq!(read("foo").unwrap(), Value::symbol("foo"));
587 }
588
589 #[test]
590 fn test_read_keyword() {
591 assert_eq!(read(":bar").unwrap(), Value::keyword("bar"));
592 }
593
594 #[test]
595 fn test_read_bool() {
596 assert_eq!(read("#t").unwrap(), Value::bool(true));
597 assert_eq!(read("#f").unwrap(), Value::bool(false));
598 }
599
600 #[test]
601 fn test_read_list() {
602 let result = read("(+ 1 2)").unwrap();
603 assert_eq!(
604 result,
605 Value::list(vec![Value::symbol("+"), Value::int(1), Value::int(2)])
606 );
607 }
608
609 #[test]
610 fn test_read_nested_list() {
611 let result = read("(* (+ 1 2) 3)").unwrap();
612 assert_eq!(
613 result,
614 Value::list(vec![
615 Value::symbol("*"),
616 Value::list(vec![Value::symbol("+"), Value::int(1), Value::int(2)]),
617 Value::int(3)
618 ])
619 );
620 }
621
622 #[test]
623 fn test_read_vector() {
624 let result = read("[1 2 3]").unwrap();
625 assert_eq!(
626 result,
627 Value::vector(vec![Value::int(1), Value::int(2), Value::int(3)])
628 );
629 }
630
631 #[test]
632 fn test_read_map() {
633 let result = read("{:a 1 :b 2}").unwrap();
634 let mut expected = BTreeMap::new();
635 expected.insert(Value::keyword("a"), Value::int(1));
636 expected.insert(Value::keyword("b"), Value::int(2));
637 assert_eq!(result, Value::map(expected));
638 }
639
640 #[test]
641 fn test_read_quote() {
642 let result = read("'foo").unwrap();
643 assert_eq!(
644 result,
645 Value::list(vec![Value::symbol("quote"), Value::symbol("foo")])
646 );
647 }
648
649 #[test]
650 fn test_read_quasiquote() {
651 let result = read("`(a ,b ,@c)").unwrap();
652 assert_eq!(
653 result,
654 Value::list(vec![
655 Value::symbol("quasiquote"),
656 Value::list(vec![
657 Value::symbol("a"),
658 Value::list(vec![Value::symbol("unquote"), Value::symbol("b")]),
659 Value::list(vec![Value::symbol("unquote-splicing"), Value::symbol("c")]),
660 ])
661 ])
662 );
663 }
664
665 #[test]
666 fn test_read_nil() {
667 assert_eq!(read("nil").unwrap(), Value::nil());
668 }
669
670 #[test]
671 fn test_read_many_exprs() {
672 let results = read_many("1 2 3").unwrap();
673 assert_eq!(results, vec![Value::int(1), Value::int(2), Value::int(3)]);
674 }
675
676 #[test]
677 fn test_comments() {
678 let result = read_many("; comment\n(+ 1 2)").unwrap();
679 assert_eq!(result.len(), 1);
680 }
681
682 #[test]
683 fn test_read_zero() {
684 assert_eq!(read("0").unwrap(), Value::int(0));
685 }
686
687 #[test]
688 fn test_read_negative_zero() {
689 assert_eq!(read("-0").unwrap(), Value::int(0));
690 }
691
692 #[test]
693 fn test_read_leading_zeros() {
694 assert_eq!(read("007").unwrap(), Value::int(7));
695 }
696
697 #[test]
698 fn test_read_large_int() {
699 assert_eq!(read("9999999999999").unwrap(), Value::int(9999999999999));
700 }
701
702 #[test]
703 fn test_read_int_overflow() {
704 assert!(read("9999999999999999999999").is_err());
706 }
707
708 #[test]
709 fn test_read_negative_float() {
710 assert_eq!(read("-2.5").unwrap(), Value::float(-2.5));
711 }
712
713 #[test]
714 fn test_read_float_leading_zero() {
715 assert_eq!(read("0.5").unwrap(), Value::float(0.5));
716 }
717
718 #[test]
719 fn test_read_minus_is_symbol() {
720 assert_eq!(read("-").unwrap(), Value::symbol("-"));
722 }
723
724 #[test]
725 fn test_read_minus_in_list() {
726 let result = read("(- 3)").unwrap();
728 assert_eq!(result, Value::list(vec![Value::symbol("-"), Value::int(3)]));
729 }
730
731 #[test]
732 fn test_read_negative_in_list() {
733 let result = read("(-3)").unwrap();
735 assert_eq!(result, Value::list(vec![Value::int(-3)]));
736 }
737
738 #[test]
739 fn test_read_empty_string() {
740 assert_eq!(read(r#""""#).unwrap(), Value::string(""));
741 }
742
743 #[test]
744 fn test_read_string_with_escapes() {
745 assert_eq!(
746 read(r#""\n\t\r\\\"" "#).unwrap(),
747 Value::string("\n\t\r\\\"")
748 );
749 }
750
751 #[test]
752 fn test_read_string_unknown_escape() {
753 assert_eq!(read(r#""\z""#).unwrap(), Value::string("\\z"));
755 }
756
757 #[test]
758 fn test_read_string_with_newline() {
759 assert_eq!(
760 read("\"line1\nline2\"").unwrap(),
761 Value::string("line1\nline2")
762 );
763 }
764
765 #[test]
766 fn test_read_unterminated_string() {
767 assert!(read("\"hello").is_err());
768 }
769
770 #[test]
771 fn test_read_string_escaped_quote_at_end() {
772 assert!(read(r#""test\""#).is_err());
774 }
775
776 #[test]
777 fn test_read_string_with_unicode() {
778 assert_eq!(read("\"héllo\"").unwrap(), Value::string("héllo"));
779 assert_eq!(read("\"日本語\"").unwrap(), Value::string("日本語"));
780 assert_eq!(read("\"🎉\"").unwrap(), Value::string("🎉"));
781 }
782
783 #[test]
784 fn test_read_string_with_parens() {
785 assert_eq!(read("\"(+ 1 2)\"").unwrap(), Value::string("(+ 1 2)"));
786 }
787
788 #[test]
789 fn test_read_operator_symbols() {
790 assert_eq!(read("+").unwrap(), Value::symbol("+"));
791 assert_eq!(read("*").unwrap(), Value::symbol("*"));
792 assert_eq!(read("/").unwrap(), Value::symbol("/"));
793 assert_eq!(read("<=").unwrap(), Value::symbol("<="));
794 assert_eq!(read(">=").unwrap(), Value::symbol(">="));
795 }
796
797 #[test]
798 fn test_read_predicate_symbols() {
799 assert_eq!(read("null?").unwrap(), Value::symbol("null?"));
800 assert_eq!(read("list?").unwrap(), Value::symbol("list?"));
801 }
802
803 #[test]
804 fn test_read_arrow_symbols() {
805 assert_eq!(
806 read("string->symbol").unwrap(),
807 Value::symbol("string->symbol")
808 );
809 }
810
811 #[test]
812 fn test_read_namespaced_symbols() {
813 assert_eq!(read("file/read").unwrap(), Value::symbol("file/read"));
814 assert_eq!(read("http/get").unwrap(), Value::symbol("http/get"));
815 }
816
817 #[test]
818 fn test_read_true_false_as_bool() {
819 assert_eq!(read("true").unwrap(), Value::bool(true));
820 assert_eq!(read("false").unwrap(), Value::bool(false));
821 }
822
823 #[test]
824 fn test_read_bare_colon_error() {
825 assert!(read(":").is_err());
827 }
828
829 #[test]
830 fn test_read_keyword_with_numbers() {
831 assert_eq!(read(":foo123").unwrap(), Value::keyword("foo123"));
832 }
833
834 #[test]
835 fn test_read_keyword_with_hyphens() {
836 assert_eq!(read(":max-turns").unwrap(), Value::keyword("max-turns"));
837 }
838
839 #[test]
840 fn test_read_hash_invalid() {
841 assert!(read("#x").is_err());
842 assert!(read("#").is_err());
843 }
844
845 #[test]
846 fn test_read_empty() {
847 assert_eq!(read("").unwrap(), Value::nil());
848 }
849
850 #[test]
851 fn test_read_whitespace_only() {
852 assert_eq!(read(" \n\t ").unwrap(), Value::nil());
853 }
854
855 #[test]
856 fn test_read_many_empty() {
857 assert_eq!(read_many("").unwrap(), vec![]);
858 }
859
860 #[test]
861 fn test_read_many_whitespace_only() {
862 assert_eq!(read_many(" \n ").unwrap(), vec![]);
863 }
864
865 #[test]
866 fn test_read_comment_only() {
867 assert_eq!(read_many("; just a comment").unwrap(), vec![]);
868 }
869
870 #[test]
871 fn test_read_empty_list() {
872 assert_eq!(read("()").unwrap(), Value::list(vec![]));
873 }
874
875 #[test]
876 fn test_read_deeply_nested() {
877 let result = read("((((42))))").unwrap();
878 assert_eq!(
879 result,
880 Value::list(vec![Value::list(vec![Value::list(vec![Value::list(
881 vec![Value::int(42)]
882 )])])])
883 );
884 }
885
886 #[test]
887 fn test_read_unterminated_list() {
888 assert!(read("(1 2").is_err());
889 }
890
891 #[test]
892 fn test_read_extra_rparen() {
893 let result = read("42").unwrap();
896 assert_eq!(result, Value::int(42));
897 }
898
899 #[test]
900 fn test_read_dotted_pair() {
901 let result = read("(a . b)").unwrap();
902 assert_eq!(
903 result,
904 Value::list(vec![
905 Value::symbol("a"),
906 Value::symbol("."),
907 Value::symbol("b")
908 ])
909 );
910 }
911
912 #[test]
913 fn test_read_empty_vector() {
914 assert_eq!(read("[]").unwrap(), Value::vector(vec![]));
915 }
916
917 #[test]
918 fn test_read_unterminated_vector() {
919 assert!(read("[1 2").is_err());
920 }
921
922 #[test]
923 fn test_read_empty_map() {
924 assert_eq!(read("{}").unwrap(), Value::map(BTreeMap::new()));
925 }
926
927 #[test]
928 fn test_read_unterminated_map() {
929 assert!(read("{:a 1").is_err());
930 }
931
932 #[test]
933 fn test_read_map_odd_elements() {
934 assert!(read("{:a 1 :b}").is_err());
935 }
936
937 #[test]
938 fn test_read_map_duplicate_keys() {
939 let result = read("{:a 1 :a 2}").unwrap();
941 let mut expected = BTreeMap::new();
942 expected.insert(Value::keyword("a"), Value::int(2));
943 assert_eq!(result, Value::map(expected));
944 }
945
946 #[test]
947 fn test_read_nested_quote() {
948 let result = read("''foo").unwrap();
949 assert_eq!(
950 result,
951 Value::list(vec![
952 Value::symbol("quote"),
953 Value::list(vec![Value::symbol("quote"), Value::symbol("foo")])
954 ])
955 );
956 }
957
958 #[test]
959 fn test_read_quote_list() {
960 let result = read("'(1 2 3)").unwrap();
961 assert_eq!(
962 result,
963 Value::list(vec![
964 Value::symbol("quote"),
965 Value::list(vec![Value::int(1), Value::int(2), Value::int(3)])
966 ])
967 );
968 }
969
970 #[test]
971 fn test_read_quote_at_eof() {
972 assert!(read("'").is_err());
973 }
974
975 #[test]
976 fn test_read_unquote_at_eof() {
977 assert!(read(",").is_err());
978 }
979
980 #[test]
981 fn test_read_unquote_splice_at_eof() {
982 assert!(read(",@").is_err());
983 }
984
985 #[test]
986 fn test_read_quasiquote_at_eof() {
987 assert!(read("`").is_err());
988 }
989
990 #[test]
991 fn test_read_comment_after_expr() {
992 assert_eq!(read_many("42 ; comment").unwrap(), vec![Value::int(42)]);
993 }
994
995 #[test]
996 fn test_read_multiple_comments() {
997 let result = read_many("; first\n; second\n42").unwrap();
998 assert_eq!(result, vec![Value::int(42)]);
999 }
1000
1001 #[test]
1002 fn test_read_comment_no_newline() {
1003 assert_eq!(read_many("; comment").unwrap(), vec![]);
1005 }
1006
1007 #[test]
1008 fn test_read_crlf_line_endings() {
1009 let result = read_many("1\r\n2\r\n3").unwrap();
1010 assert_eq!(result, vec![Value::int(1), Value::int(2), Value::int(3)]);
1011 }
1012
1013 #[test]
1014 fn test_read_tabs_as_whitespace() {
1015 assert_eq!(
1016 read("(\t+\t1\t2\t)").unwrap(),
1017 Value::list(vec![Value::symbol("+"), Value::int(1), Value::int(2)])
1018 );
1019 }
1020
1021 #[test]
1022 fn test_read_mixed_collections() {
1023 let result = read("([1 2] {:a 3})").unwrap();
1025 let mut map = BTreeMap::new();
1026 map.insert(Value::keyword("a"), Value::int(3));
1027 assert_eq!(
1028 result,
1029 Value::list(vec![
1030 Value::vector(vec![Value::int(1), Value::int(2)]),
1031 Value::map(map)
1032 ])
1033 );
1034 }
1035
1036 #[test]
1037 fn test_read_many_mixed_types() {
1038 let result = read_many(r#"42 3.14 "hello" foo :bar #t nil"#).unwrap();
1039 assert_eq!(result.len(), 7);
1040 assert_eq!(result[0], Value::int(42));
1041 assert_eq!(result[1], Value::float(3.14));
1042 assert_eq!(result[2], Value::string("hello"));
1043 assert_eq!(result[3], Value::symbol("foo"));
1044 assert_eq!(result[4], Value::keyword("bar"));
1045 assert_eq!(result[5], Value::bool(true));
1046 assert_eq!(result[6], Value::nil());
1047 }
1048
1049 #[test]
1050 fn test_span_map_tracks_lists() {
1051 let (exprs, spans) = read_many_with_spans("(+ 1 2)").unwrap();
1052 assert_eq!(exprs.len(), 1);
1053 let rc = exprs[0].as_list_rc().expect("expected list");
1055 let ptr = Rc::as_ptr(&rc) as usize;
1056 let span = spans.get(&ptr).expect("list should have span");
1057 assert_eq!(span.line, 1);
1058 assert_eq!(span.col, 1);
1059 }
1060
1061 #[test]
1062 fn test_span_map_multiline() {
1063 let (exprs, spans) = read_many_with_spans("(foo)\n(bar)").unwrap();
1064 assert_eq!(exprs.len(), 2);
1065 let rc = exprs[1].as_list_rc().expect("expected list");
1066 let ptr = Rc::as_ptr(&rc) as usize;
1067 let span = spans.get(&ptr).expect("second list should have span");
1068 assert_eq!(span.line, 2);
1069 assert_eq!(span.col, 1);
1070 }
1071
1072 #[test]
1073 fn test_read_unexpected_char() {
1074 assert!(read("@").is_err());
1075 assert!(read("$").is_err());
1076 }
1077
1078 #[test]
1079 fn test_read_char_literal() {
1080 assert_eq!(read("#\\a").unwrap(), Value::char('a'));
1081 assert_eq!(read("#\\Z").unwrap(), Value::char('Z'));
1082 assert_eq!(read("#\\0").unwrap(), Value::char('0'));
1083 }
1084
1085 #[test]
1086 fn test_read_char_named() {
1087 assert_eq!(read("#\\space").unwrap(), Value::char(' '));
1088 assert_eq!(read("#\\newline").unwrap(), Value::char('\n'));
1089 assert_eq!(read("#\\tab").unwrap(), Value::char('\t'));
1090 assert_eq!(read("#\\return").unwrap(), Value::char('\r'));
1091 assert_eq!(read("#\\nul").unwrap(), Value::char('\0'));
1092 }
1093
1094 #[test]
1095 fn test_read_char_special() {
1096 assert_eq!(read("#\\(").unwrap(), Value::char('('));
1097 assert_eq!(read("#\\)").unwrap(), Value::char(')'));
1098 }
1099
1100 #[test]
1101 fn test_read_char_in_list() {
1102 let result = read("(#\\a #\\b)").unwrap();
1103 assert_eq!(
1104 result,
1105 Value::list(vec![Value::char('a'), Value::char('b')])
1106 );
1107 }
1108
1109 #[test]
1110 fn test_read_char_unknown_name() {
1111 assert!(read("#\\foobar").is_err());
1112 }
1113
1114 #[test]
1115 fn test_read_char_eof() {
1116 assert!(read("#\\").is_err());
1117 }
1118
1119 #[test]
1120 fn test_read_bytevector_literal() {
1121 assert_eq!(
1122 read("#u8(1 2 3)").unwrap(),
1123 Value::bytevector(vec![1, 2, 3])
1124 );
1125 }
1126
1127 #[test]
1128 fn test_read_bytevector_empty() {
1129 assert_eq!(read("#u8()").unwrap(), Value::bytevector(vec![]));
1130 }
1131
1132 #[test]
1133 fn test_read_bytevector_single() {
1134 assert_eq!(read("#u8(255)").unwrap(), Value::bytevector(vec![255]));
1135 }
1136
1137 #[test]
1138 fn test_read_bytevector_out_of_range() {
1139 assert!(read("#u8(256)").is_err());
1140 }
1141
1142 #[test]
1143 fn test_read_bytevector_negative() {
1144 assert!(read("#u8(-1)").is_err());
1145 }
1146
1147 #[test]
1148 fn test_read_bytevector_non_integer() {
1149 assert!(read("#u8(1.5)").is_err());
1150 }
1151
1152 #[test]
1153 fn test_read_bytevector_unterminated() {
1154 assert!(read("#u8(1 2").is_err());
1155 }
1156
1157 #[test]
1158 fn test_read_bytevector_in_list() {
1159 let result = read("(#u8(1 2) #u8(3))").unwrap();
1160 assert_eq!(
1161 result,
1162 Value::list(vec![
1163 Value::bytevector(vec![1, 2]),
1164 Value::bytevector(vec![3]),
1165 ])
1166 );
1167 }
1168
1169 #[test]
1170 fn test_read_string_hex_escape_basic() {
1171 let result = read(r#""\x41;""#).unwrap();
1173 assert_eq!(result, Value::string("A"));
1174 }
1175
1176 #[test]
1177 fn test_read_string_hex_escape_lowercase() {
1178 let result = read(r#""\x6c;""#).unwrap();
1179 assert_eq!(result, Value::string("l"));
1180 }
1181
1182 #[test]
1183 fn test_read_string_hex_escape_mixed_case() {
1184 let result = read(r#""\x4F;""#).unwrap();
1185 assert_eq!(result, Value::string("O"));
1186 }
1187
1188 #[test]
1189 fn test_read_string_hex_escape_esc_char() {
1190 let result = read(r#""\x1B;""#).unwrap();
1192 assert_eq!(result, Value::string("\x1B"));
1193 }
1194
1195 #[test]
1196 fn test_read_string_hex_escape_null() {
1197 let result = read(r#""\x0;""#).unwrap();
1198 assert_eq!(result, Value::string("\0"));
1199 }
1200
1201 #[test]
1202 fn test_read_string_hex_escape_unicode() {
1203 let result = read(r#""\x3BB;""#).unwrap();
1205 assert_eq!(result, Value::string("λ"));
1206 }
1207
1208 #[test]
1209 fn test_read_string_hex_escape_emoji() {
1210 let result = read(r#""\x1F600;""#).unwrap();
1212 assert_eq!(result, Value::string("😀"));
1213 }
1214
1215 #[test]
1216 fn test_read_string_hex_escape_in_context() {
1217 let result = read(r#""hello\x20;world""#).unwrap();
1219 assert_eq!(result, Value::string("hello world"));
1220 }
1221
1222 #[test]
1223 fn test_read_string_hex_escape_multiple() {
1224 let result = read(r#""\x48;\x69;""#).unwrap();
1225 assert_eq!(result, Value::string("Hi"));
1226 }
1227
1228 #[test]
1229 fn test_read_string_hex_escape_missing_semicolon() {
1230 assert!(read(r#""\x41""#).is_err());
1231 }
1232
1233 #[test]
1234 fn test_read_string_hex_escape_no_digits() {
1235 assert!(read(r#""\x;""#).is_err());
1236 }
1237
1238 #[test]
1239 fn test_read_string_hex_escape_invalid_hex() {
1240 assert!(read(r#""\xGG;""#).is_err());
1241 }
1242
1243 #[test]
1244 fn test_read_string_hex_escape_invalid_codepoint() {
1245 assert!(read(r#""\xD800;""#).is_err());
1247 }
1248
1249 #[test]
1250 fn test_read_string_hex_escape_too_large() {
1251 assert!(read(r#""\x110000;""#).is_err());
1253 }
1254
1255 #[test]
1256 fn test_read_string_u_escape_basic() {
1257 let result = read(r#""\u0041""#).unwrap();
1259 assert_eq!(result, Value::string("A"));
1260 }
1261
1262 #[test]
1263 fn test_read_string_u_escape_lambda() {
1264 let result = read(r#""\u03BB""#).unwrap();
1265 assert_eq!(result, Value::string("λ"));
1266 }
1267
1268 #[test]
1269 fn test_read_string_u_escape_esc() {
1270 let result = read(r#""\u001B""#).unwrap();
1271 assert_eq!(result, Value::string("\x1B"));
1272 }
1273
1274 #[test]
1275 fn test_read_string_u_escape_too_few_digits() {
1276 assert!(read(r#""\u041""#).is_err());
1277 }
1278
1279 #[test]
1280 fn test_read_string_u_escape_surrogate() {
1281 assert!(read(r#""\uD800""#).is_err());
1282 }
1283
1284 #[test]
1285 fn test_read_string_big_u_escape_basic() {
1286 let result = read(r#""\U00000041""#).unwrap();
1287 assert_eq!(result, Value::string("A"));
1288 }
1289
1290 #[test]
1291 fn test_read_string_big_u_escape_emoji() {
1292 let result = read(r#""\U0001F600""#).unwrap();
1293 assert_eq!(result, Value::string("😀"));
1294 }
1295
1296 #[test]
1297 fn test_read_string_big_u_escape_too_few_digits() {
1298 assert!(read(r#""\U0041""#).is_err());
1299 }
1300
1301 #[test]
1302 fn test_read_string_big_u_escape_invalid() {
1303 assert!(read(r#""\U00110000""#).is_err());
1304 }
1305
1306 #[test]
1307 fn test_read_string_null_escape() {
1308 let result = read(r#""\0""#).unwrap();
1309 assert_eq!(result, Value::string("\0"));
1310 }
1311
1312 #[test]
1313 fn test_read_string_mixed_escapes() {
1314 let result = read(r#""\x48;\u0069\n\t""#).unwrap();
1316 assert_eq!(result, Value::string("Hi\n\t"));
1317 }
1318
1319 #[test]
1320 fn test_read_string_ansi_escape_sequence() {
1321 let result = read(r#""\x1B;[31mRed\x1B;[0m""#).unwrap();
1323 assert_eq!(result, Value::string("\x1B[31mRed\x1B[0m"));
1324 }
1325
1326 #[test]
1329 fn test_read_fstring_no_interpolation() {
1330 let result = read(r#"f"hello""#).unwrap();
1331 assert_eq!(
1332 result,
1333 Value::list(vec![Value::symbol("str"), Value::string("hello")])
1334 );
1335 }
1336
1337 #[test]
1338 fn test_read_fstring_single_var() {
1339 let result = read(r#"f"hello ${name}""#).unwrap();
1340 assert_eq!(
1341 result,
1342 Value::list(vec![
1343 Value::symbol("str"),
1344 Value::string("hello "),
1345 Value::symbol("name"),
1346 ])
1347 );
1348 }
1349
1350 #[test]
1351 fn test_read_fstring_multiple_vars() {
1352 let result = read(r#"f"${a} and ${b}""#).unwrap();
1353 assert_eq!(
1354 result,
1355 Value::list(vec![
1356 Value::symbol("str"),
1357 Value::symbol("a"),
1358 Value::string(" and "),
1359 Value::symbol("b"),
1360 ])
1361 );
1362 }
1363
1364 #[test]
1365 fn test_read_fstring_expression() {
1366 let result = read(r#"f"result: ${(+ 1 2)}""#).unwrap();
1367 assert_eq!(
1368 result,
1369 Value::list(vec![
1370 Value::symbol("str"),
1371 Value::string("result: "),
1372 Value::list(vec![Value::symbol("+"), Value::int(1), Value::int(2),]),
1373 ])
1374 );
1375 }
1376
1377 #[test]
1378 fn test_read_fstring_escaped_dollar() {
1379 let result = read(r#"f"costs \$5""#).unwrap();
1380 assert_eq!(
1381 result,
1382 Value::list(vec![Value::symbol("str"), Value::string("costs $5")])
1383 );
1384 }
1385
1386 #[test]
1387 fn test_read_fstring_dollar_without_brace() {
1388 let result = read(r#"f"costs $5""#).unwrap();
1389 assert_eq!(
1390 result,
1391 Value::list(vec![Value::symbol("str"), Value::string("costs $5")])
1392 );
1393 }
1394
1395 #[test]
1396 fn test_read_fstring_escape_sequences() {
1397 let result = read(r#"f"line1\nline2""#).unwrap();
1398 assert_eq!(
1399 result,
1400 Value::list(vec![Value::symbol("str"), Value::string("line1\nline2"),])
1401 );
1402 }
1403
1404 #[test]
1405 fn test_read_fstring_empty_interpolation_error() {
1406 assert!(read(r#"f"hello ${}""#).is_err());
1407 }
1408
1409 #[test]
1410 fn test_read_fstring_unterminated_interpolation_error() {
1411 assert!(read(r#"f"hello ${name""#).is_err());
1412 }
1413
1414 #[test]
1415 fn test_read_fstring_unterminated_string_error() {
1416 assert!(read(r#"f"hello"#).is_err());
1417 }
1418
1419 #[test]
1420 fn test_read_fstring_keyword_access() {
1421 let result = read(r#"f"name: ${(:name user)}""#).unwrap();
1422 assert_eq!(
1423 result,
1424 Value::list(vec![
1425 Value::symbol("str"),
1426 Value::string("name: "),
1427 Value::list(vec![Value::keyword("name"), Value::symbol("user")]),
1428 ])
1429 );
1430 }
1431
1432 #[test]
1433 fn test_read_fstring_in_list() {
1434 let result = read(r#"(println f"hello ${name}")"#).unwrap();
1435 assert_eq!(
1436 result,
1437 Value::list(vec![
1438 Value::symbol("println"),
1439 Value::list(vec![
1440 Value::symbol("str"),
1441 Value::string("hello "),
1442 Value::symbol("name"),
1443 ]),
1444 ])
1445 );
1446 }
1447
1448 #[test]
1449 fn test_read_fstring_empty() {
1450 let result = read(r#"f"""#).unwrap();
1451 assert_eq!(result, Value::list(vec![Value::symbol("str")]));
1452 }
1453
1454 #[test]
1455 fn test_read_fstring_only_expr() {
1456 let result = read(r#"f"${x}""#).unwrap();
1457 assert_eq!(
1458 result,
1459 Value::list(vec![Value::symbol("str"), Value::symbol("x")])
1460 );
1461 }
1462
1463 #[test]
1464 fn test_read_f_symbol_still_works() {
1465 let result = read("f").unwrap();
1467 assert_eq!(result, Value::symbol("f"));
1468 }
1469
1470 #[test]
1471 fn test_read_f_prefixed_symbol_still_works() {
1472 let result = read("foo").unwrap();
1474 assert_eq!(result, Value::symbol("foo"));
1475 }
1476
1477 #[test]
1480 fn test_read_short_lambda_single_arg() {
1481 let result = read("#(+ % 1)").unwrap();
1483 assert_eq!(
1484 result,
1485 Value::list(vec![
1486 Value::symbol("lambda"),
1487 Value::list(vec![Value::symbol("%1")]),
1488 Value::list(vec![Value::symbol("+"), Value::symbol("%1"), Value::int(1),]),
1489 ])
1490 );
1491 }
1492
1493 #[test]
1494 fn test_read_short_lambda_two_args() {
1495 let result = read("#(+ %1 %2)").unwrap();
1497 assert_eq!(
1498 result,
1499 Value::list(vec![
1500 Value::symbol("lambda"),
1501 Value::list(vec![Value::symbol("%1"), Value::symbol("%2")]),
1502 Value::list(vec![
1503 Value::symbol("+"),
1504 Value::symbol("%1"),
1505 Value::symbol("%2"),
1506 ]),
1507 ])
1508 );
1509 }
1510
1511 #[test]
1512 fn test_read_short_lambda_bare_percent_is_percent1() {
1513 let result = read("#(* % %)").unwrap();
1515 assert_eq!(
1516 result,
1517 Value::list(vec![
1518 Value::symbol("lambda"),
1519 Value::list(vec![Value::symbol("%1")]),
1520 Value::list(vec![
1521 Value::symbol("*"),
1522 Value::symbol("%1"),
1523 Value::symbol("%1"),
1524 ]),
1525 ])
1526 );
1527 }
1528
1529 #[test]
1530 fn test_read_short_lambda_no_args() {
1531 let result = read(r#"#(println "hello")"#).unwrap();
1533 assert_eq!(
1534 result,
1535 Value::list(vec![
1536 Value::symbol("lambda"),
1537 Value::list(vec![]),
1538 Value::list(vec![Value::symbol("println"), Value::string("hello"),]),
1539 ])
1540 );
1541 }
1542
1543 #[test]
1544 fn test_read_short_lambda_in_list() {
1545 let result = read("(map #(+ % 1) numbers)").unwrap();
1547 assert_eq!(
1548 result,
1549 Value::list(vec![
1550 Value::symbol("map"),
1551 Value::list(vec![
1552 Value::symbol("lambda"),
1553 Value::list(vec![Value::symbol("%1")]),
1554 Value::list(vec![Value::symbol("+"), Value::symbol("%1"), Value::int(1),]),
1555 ]),
1556 Value::symbol("numbers"),
1557 ])
1558 );
1559 }
1560
1561 #[test]
1562 fn test_read_short_lambda_unterminated() {
1563 assert!(read("#(+ % 1").is_err());
1564 }
1565
1566 #[test]
1567 fn test_read_short_lambda_nested_expr() {
1568 let result = read("#(> (string-length %) 3)").unwrap();
1570 assert_eq!(
1571 result,
1572 Value::list(vec![
1573 Value::symbol("lambda"),
1574 Value::list(vec![Value::symbol("%1")]),
1575 Value::list(vec![
1576 Value::symbol(">"),
1577 Value::list(vec![Value::symbol("string-length"), Value::symbol("%1"),]),
1578 Value::int(3),
1579 ]),
1580 ])
1581 );
1582 }
1583
1584 #[test]
1585 fn test_read_regex_literal_digits() {
1586 let result = read(r#"#"\d+""#).unwrap();
1587 assert_eq!(result, Value::string(r"\d+"));
1588 }
1589
1590 #[test]
1591 fn test_read_regex_literal_char_class() {
1592 let result = read(r#"#"[a-z]+""#).unwrap();
1593 assert_eq!(result, Value::string("[a-z]+"));
1594 }
1595
1596 #[test]
1597 fn test_read_regex_literal_backslashes_literal() {
1598 let result = read(r#"#"hello\.world""#).unwrap();
1599 assert_eq!(result, Value::string(r"hello\.world"));
1600 }
1601
1602 #[test]
1603 fn test_read_regex_literal_escaped_quote() {
1604 let result = read(r#"#"foo\"bar""#).unwrap();
1605 assert_eq!(result, Value::string(r#"foo"bar"#));
1606 }
1607
1608 #[test]
1609 fn test_read_regex_literal_unterminated() {
1610 assert!(read(r#"#"abc"#).is_err());
1611 }
1612
1613 #[test]
1614 fn test_mismatched_paren_bracket() {
1615 let err = read("(list [1 2 3)").unwrap_err();
1616 let msg = err.to_string();
1617 assert!(
1618 msg.contains("mismatched"),
1619 "expected mismatched error, got: {msg}"
1620 );
1621 }
1622
1623 #[test]
1624 fn test_mismatched_bracket_paren() {
1625 let err = read("[1 2 3)").unwrap_err();
1626 let msg = err.to_string();
1627 assert!(
1628 msg.contains("mismatched"),
1629 "expected mismatched error, got: {msg}"
1630 );
1631 }
1632
1633 #[test]
1634 fn test_mismatched_paren_brace() {
1635 let err = read("(+ 1 2}").unwrap_err();
1636 let msg = err.to_string();
1637 assert!(
1638 msg.contains("mismatched"),
1639 "expected mismatched error, got: {msg}"
1640 );
1641 }
1642
1643 #[test]
1644 fn test_mismatched_brace_paren() {
1645 let err = read("{:a 1)").unwrap_err();
1646 let msg = err.to_string();
1647 assert!(
1648 msg.contains("mismatched"),
1649 "expected mismatched error, got: {msg}"
1650 );
1651 }
1652
1653 #[test]
1654 fn test_mismatched_brace_bracket() {
1655 let err = read("{:a 1]").unwrap_err();
1656 let msg = err.to_string();
1657 assert!(
1658 msg.contains("mismatched"),
1659 "expected mismatched error, got: {msg}"
1660 );
1661 }
1662
1663 #[test]
1664 fn test_mismatched_bracket_brace() {
1665 let err = read("[1 2}").unwrap_err();
1666 let msg = err.to_string();
1667 assert!(
1668 msg.contains("mismatched"),
1669 "expected mismatched error, got: {msg}"
1670 );
1671 }
1672
1673 #[test]
1674 fn test_correct_brackets_still_work() {
1675 assert!(read("(list [1 2 3])").is_ok());
1676 assert!(read("{:a 1}").is_ok());
1677 assert!(read("[1 [2 3] 4]").is_ok());
1678 }
1679
1680 #[test]
1681 fn test_auto_gensym_symbol_parsing() {
1682 let val = read("v#").unwrap();
1683 assert_eq!(val.as_symbol().unwrap(), "v#");
1684
1685 let val = read("tmp#").unwrap();
1686 assert_eq!(val.as_symbol().unwrap(), "tmp#");
1687
1688 let val = read("`(let ((v# 1)) v#)").unwrap();
1689 let items = val.as_list().unwrap();
1690 assert_eq!(items[0].as_symbol().unwrap(), "quasiquote");
1691 }
1692
1693 #[test]
1694 fn test_hash_reader_dispatch_still_works() {
1695 let val = read("#t").unwrap();
1696 assert_eq!(val.as_bool(), Some(true));
1697
1698 let val = read("#f").unwrap();
1699 assert_eq!(val.as_bool(), Some(false));
1700
1701 let val = read("#\\space").unwrap();
1702 assert_eq!(val.as_char(), Some(' '));
1703
1704 let val = read("#(+ % 1)").unwrap();
1705 assert!(val.as_list().is_some());
1706 }
1707
1708 #[test]
1709 fn test_auto_gensym_edge_cases() {
1710 let val = read("x##").unwrap();
1711 assert_eq!(val.as_symbol().unwrap(), "x##");
1712
1713 let val = read(":foo").unwrap();
1714 assert!(val.as_keyword().is_some());
1715 }
1716}