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