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