1use crate::scheme::value::Value;
40use std::fmt;
41
42#[derive(Debug, Clone, PartialEq)]
48pub enum Token {
49 Integer(i64),
51 Real(f64),
52 String(String),
53 Char(char),
54 Symbol(String),
55 Keyword(String),
56 Bool(bool),
57
58 LeftParen, RightParen, LeftBracket, RightBracket, Dot, Quote, Quasiquote, Unquote, UnquoteSplicing, VectorStart, Eof,
76}
77
78impl fmt::Display for Token {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 match self {
81 Token::Integer(n) => write!(f, "{}", n),
82 Token::Real(n) => write!(f, "{}", n),
83 Token::String(s) => write!(f, "\"{}\"", s),
84 Token::Char(ch) => write!(f, "#\\{}", ch),
85 Token::Symbol(s) => write!(f, "{}", s),
86 Token::Keyword(s) => write!(f, "#:{}", s),
87 Token::Bool(b) => write!(f, "{}", if *b { "#t" } else { "#f" }),
88 Token::LeftParen => write!(f, "("),
89 Token::RightParen => write!(f, ")"),
90 Token::LeftBracket => write!(f, "["),
91 Token::RightBracket => write!(f, "]"),
92 Token::Dot => write!(f, "."),
93 Token::Quote => write!(f, "'"),
94 Token::Quasiquote => write!(f, "`"),
95 Token::Unquote => write!(f, ","),
96 Token::UnquoteSplicing => write!(f, ",@"),
97 Token::VectorStart => write!(f, "#("),
98 Token::Eof => write!(f, "<EOF>"),
99 }
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub struct Position {
112 pub line: usize,
113 pub column: usize,
114}
115
116impl Position {
117 pub fn new() -> Self {
118 Position { line: 1, column: 1 }
119 }
120}
121
122impl Default for Position {
123 fn default() -> Self {
124 Self::new()
125 }
126}
127
128impl fmt::Display for Position {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "{}:{}", self.line, self.column)
131 }
132}
133
134#[derive(Debug, Clone)]
140pub struct ParseError {
141 pub message: String,
142 pub position: Position,
143}
144
145impl ParseError {
146 pub fn new(message: String, position: Position) -> Self {
147 ParseError { message, position }
148 }
149}
150
151impl fmt::Display for ParseError {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(f, "Parse error at {}: {}", self.position, self.message)
154 }
155}
156
157impl std::error::Error for ParseError {}
158
159pub type ParseResult<T> = Result<T, ParseError>;
160
161pub struct Tokenizer {
181 input: Vec<char>,
183
184 pos: usize,
186
187 line: usize,
189
190 column: usize,
192
193 peeked: Option<Token>,
195}
196
197impl Tokenizer {
198 pub fn new(input: &str) -> Self {
200 Tokenizer {
201 input: input.chars().collect(),
202 pos: 0,
203 line: 1,
204 column: 1,
205 peeked: None,
206 }
207 }
208
209 pub fn position(&self) -> Position {
211 Position {
212 line: self.line,
213 column: self.column,
214 }
215 }
216
217 fn peek_char(&self) -> Option<char> {
219 if self.pos < self.input.len() {
220 Some(self.input[self.pos])
221 } else {
222 None
223 }
224 }
225
226 fn peek_char_at(&self, offset: usize) -> Option<char> {
228 let index = self.pos + offset;
229 if index < self.input.len() {
230 Some(self.input[index])
231 } else {
232 None
233 }
234 }
235
236 fn next_char(&mut self) -> Option<char> {
238 if self.pos < self.input.len() {
239 let ch = self.input[self.pos];
240 self.pos += 1;
241
242 if ch == '\n' {
244 self.line += 1;
245 self.column = 1;
246 } else {
247 self.column += 1;
248 }
249
250 Some(ch)
251 } else {
252 None
253 }
254 }
255
256 fn skip_whitespace(&mut self) {
260 loop {
261 match self.peek_char() {
262 Some(ch) if ch.is_whitespace() => {
264 self.next_char();
265 }
266
267 Some(';') => {
269 self.next_char();
270 while let Some(ch) = self.peek_char() {
271 self.next_char();
272 if ch == '\n' {
273 break;
274 }
275 }
276 }
277
278 Some('#') if self.peek_char_at(1) == Some('|') => {
280 self.next_char(); self.next_char(); let mut depth = 1;
285 while depth > 0 {
286 match self.next_char() {
287 Some('|') if self.peek_char() == Some('#') => {
288 self.next_char(); depth -= 1;
290 }
291 Some('#') if self.peek_char() == Some('|') => {
292 self.next_char(); depth += 1; }
295 Some(_) => {} None => break, }
298 }
299 }
300
301 _ => break,
303 }
304 }
305 }
306
307 fn is_delimiter(ch: char) -> bool {
309 ch.is_whitespace()
310 || matches!(
311 ch,
312 '(' | ')' | '[' | ']' | '"' | ';' | ',' | '`' | '\''
313 )
314 }
315
316 fn parse_number(&mut self, start_pos: Position) -> ParseResult<Token> {
318 let mut num_str = String::new();
319
320 while let Some(ch) = self.peek_char() {
322 if ch.is_ascii_digit() || matches!(ch, '.' | 'e' | 'E' | '+' | '-') {
323 num_str.push(ch);
324 self.next_char();
325 } else if Self::is_delimiter(ch) {
326 break;
327 } else {
328 return Err(ParseError::new(
330 format!("Invalid character in number: {}", ch),
331 start_pos,
332 ));
333 }
334 }
335
336 if let Ok(n) = num_str.parse::<i64>() {
338 return Ok(Token::Integer(n));
339 }
340
341 if let Ok(n) = num_str.parse::<f64>() {
343 return Ok(Token::Real(n));
344 }
345
346 Err(ParseError::new(
347 format!("Invalid number: {}", num_str),
348 start_pos,
349 ))
350 }
351
352 fn parse_hex_number(&mut self, start_pos: Position) -> ParseResult<Token> {
354 let mut num_str = String::new();
355
356 while let Some(ch) = self.peek_char() {
357 if ch.is_ascii_hexdigit() {
358 num_str.push(ch);
359 self.next_char();
360 } else if Self::is_delimiter(ch) {
361 break;
362 } else {
363 return Err(ParseError::new(
364 format!("Invalid character in hex number: {}", ch),
365 start_pos,
366 ));
367 }
368 }
369
370 if num_str.is_empty() {
371 return Err(ParseError::new("Empty hex number".to_string(), start_pos));
372 }
373
374 i64::from_str_radix(&num_str, 16)
375 .map(Token::Integer)
376 .map_err(|_| ParseError::new(format!("Invalid hex number: {}", num_str), start_pos))
377 }
378
379 fn parse_octal_number(&mut self, start_pos: Position) -> ParseResult<Token> {
381 let mut num_str = String::new();
382
383 while let Some(ch) = self.peek_char() {
384 if ch.is_digit(8) {
385 num_str.push(ch);
386 self.next_char();
387 } else if Self::is_delimiter(ch) {
388 break;
389 } else {
390 return Err(ParseError::new(
391 format!("Invalid character in octal number: {}", ch),
392 start_pos,
393 ));
394 }
395 }
396
397 if num_str.is_empty() {
398 return Err(ParseError::new("Empty octal number".to_string(), start_pos));
399 }
400
401 i64::from_str_radix(&num_str, 8)
402 .map(Token::Integer)
403 .map_err(|_| ParseError::new(format!("Invalid octal number: {}", num_str), start_pos))
404 }
405
406 fn parse_binary_number(&mut self, start_pos: Position) -> ParseResult<Token> {
408 let mut num_str = String::new();
409
410 while let Some(ch) = self.peek_char() {
411 if matches!(ch, '0' | '1') {
412 num_str.push(ch);
413 self.next_char();
414 } else if Self::is_delimiter(ch) {
415 break;
416 } else {
417 return Err(ParseError::new(
418 format!("Invalid character in binary number: {}", ch),
419 start_pos,
420 ));
421 }
422 }
423
424 if num_str.is_empty() {
425 return Err(ParseError::new("Empty binary number".to_string(), start_pos));
426 }
427
428 i64::from_str_radix(&num_str, 2)
429 .map(Token::Integer)
430 .map_err(|_| ParseError::new(format!("Invalid binary number: {}", num_str), start_pos))
431 }
432
433 fn parse_symbol(&mut self) -> String {
435 let mut sym = String::new();
436
437 while let Some(ch) = self.peek_char() {
438 if Self::is_delimiter(ch) {
439 break;
440 }
441 sym.push(ch);
442 self.next_char();
443 }
444
445 sym
446 }
447
448 fn parse_string(&mut self, start_pos: Position) -> ParseResult<String> {
450 self.next_char(); let mut result = String::new();
453
454 loop {
455 match self.next_char() {
456 Some('"') => {
457 return Ok(result);
459 }
460 Some('\\') => {
461 match self.next_char() {
463 Some('n') => result.push('\n'),
464 Some('t') => result.push('\t'),
465 Some('r') => result.push('\r'),
466 Some('\\') => result.push('\\'),
467 Some('"') => result.push('"'),
468 Some(ch) => result.push(ch), None => {
470 return Err(ParseError::new(
471 "Unexpected EOF in string escape".to_string(),
472 start_pos,
473 ))
474 }
475 }
476 }
477 Some(ch) => {
478 result.push(ch);
479 }
480 None => {
481 return Err(ParseError::new(
482 "Unexpected EOF in string".to_string(),
483 start_pos,
484 ))
485 }
486 }
487 }
488 }
489
490 fn parse_char(&mut self, start_pos: Position) -> ParseResult<char> {
493 if self.next_char() != Some('\\') {
495 return Err(ParseError::new(
496 "Expected \\ after # in character literal".to_string(),
497 start_pos,
498 ));
499 }
500
501 let mut name = String::new();
503 while let Some(ch) = self.peek_char() {
504 if Self::is_delimiter(ch) {
505 break;
506 }
507 name.push(ch);
508 self.next_char();
509 }
510
511 if name.is_empty() {
512 return Err(ParseError::new(
513 "Empty character literal".to_string(),
514 start_pos,
515 ));
516 }
517
518 match name.as_str() {
520 "space" => Ok(' '),
521 "newline" => Ok('\n'),
522 "tab" => Ok('\t'),
523 "return" => Ok('\r'),
524 s if s.len() == 1 => Ok(s.chars().next().unwrap()),
525 _ => Err(ParseError::new(
526 format!("Invalid character literal: #\\{}", name),
527 start_pos,
528 )),
529 }
530 }
531
532 pub fn next_token(&mut self) -> ParseResult<Token> {
534 if let Some(tok) = self.peeked.take() {
536 return Ok(tok);
537 }
538
539 self.skip_whitespace();
541
542 let start_pos = self.position();
543
544 match self.peek_char() {
545 None => Ok(Token::Eof),
546
547 Some('(') => {
548 self.next_char();
549 Ok(Token::LeftParen)
550 }
551
552 Some(')') => {
553 self.next_char();
554 Ok(Token::RightParen)
555 }
556
557 Some('[') => {
558 self.next_char();
559 Ok(Token::LeftBracket)
560 }
561
562 Some(']') => {
563 self.next_char();
564 Ok(Token::RightBracket)
565 }
566
567 Some('\'') => {
568 self.next_char();
569 Ok(Token::Quote)
570 }
571
572 Some('`') => {
573 self.next_char();
574 Ok(Token::Quasiquote)
575 }
576
577 Some(',') => {
578 self.next_char();
579 if self.peek_char() == Some('@') {
581 self.next_char();
582 Ok(Token::UnquoteSplicing)
583 } else {
584 Ok(Token::Unquote)
585 }
586 }
587
588 Some('"') => {
589 let s = self.parse_string(start_pos)?;
590 Ok(Token::String(s))
591 }
592
593 Some('#') => {
594 self.next_char(); match self.peek_char() {
596 Some('t') => {
597 self.next_char();
598 Ok(Token::Bool(true))
599 }
600 Some('f') => {
601 self.next_char();
602 Ok(Token::Bool(false))
603 }
604 Some('(') => {
605 self.next_char();
606 Ok(Token::VectorStart)
607 }
608 Some('\\') => {
609 let ch = self.parse_char(start_pos)?;
610 Ok(Token::Char(ch))
611 }
612 Some(':') => {
613 self.next_char(); let name = self.parse_symbol();
615 Ok(Token::Keyword(name))
616 }
617 Some('x') | Some('X') => {
618 self.next_char(); self.parse_hex_number(start_pos)
620 }
621 Some('o') | Some('O') => {
622 self.next_char(); self.parse_octal_number(start_pos)
624 }
625 Some('b') | Some('B') => {
626 self.next_char(); self.parse_binary_number(start_pos)
628 }
629 _ => Err(ParseError::new(
630 format!("Invalid # syntax: #{:?}", self.peek_char()),
631 start_pos,
632 )),
633 }
634 }
635
636 Some(ch) if ch.is_ascii_digit() => self.parse_number(start_pos),
637
638 Some('+') | Some('-') => {
639 if let Some(next) = self.peek_char_at(1) {
641 if next.is_ascii_digit() {
642 self.parse_number(start_pos)
643 } else {
644 let sym = self.parse_symbol();
645 Ok(Token::Symbol(sym))
646 }
647 } else {
648 let sym = self.parse_symbol();
649 Ok(Token::Symbol(sym))
650 }
651 }
652
653 Some('.') => {
654 if let Some(next) = self.peek_char_at(1) {
656 if next.is_ascii_digit() {
657 self.parse_number(start_pos)
658 } else {
659 self.next_char();
660 Ok(Token::Dot)
661 }
662 } else {
663 self.next_char();
664 Ok(Token::Dot)
665 }
666 }
667
668 Some(_) => {
669 let sym = self.parse_symbol();
671 Ok(Token::Symbol(sym))
672 }
673 }
674 }
675
676 pub fn peek_token(&mut self) -> ParseResult<&Token> {
678 if self.peeked.is_none() {
679 let tok = self.next_token()?;
680 self.peeked = Some(tok);
681 }
682 Ok(self.peeked.as_ref().unwrap())
683 }
684}
685
686pub struct Parser {
701 tokenizer: Tokenizer,
702}
703
704impl Parser {
705 pub fn new(input: &str) -> Self {
707 Parser {
708 tokenizer: Tokenizer::new(input),
709 }
710 }
711
712 pub fn parse(&mut self) -> ParseResult<Value> {
716 self.parse_expr()
717 }
718
719 pub fn parse_all(&mut self) -> ParseResult<Vec<Value>> {
723 let mut exprs = Vec::new();
724
725 loop {
726 let tok = self.tokenizer.peek_token()?;
727 if *tok == Token::Eof {
728 break;
729 }
730 exprs.push(self.parse_expr()?);
731 }
732
733 Ok(exprs)
734 }
735
736 fn parse_expr(&mut self) -> ParseResult<Value> {
738 let start_pos = self.tokenizer.position();
739 let tok = self.tokenizer.next_token()?;
740
741 match tok {
742 Token::Integer(n) => Ok(Value::integer(n)),
744 Token::Real(n) => Ok(Value::real(n)),
745 Token::String(s) => Ok(Value::string(s)),
746 Token::Char(ch) => Ok(Value::char(ch)),
747 Token::Bool(b) => Ok(Value::bool(b)),
748 Token::Symbol(s) => Ok(Value::symbol(&s)),
749 Token::Keyword(s) => Ok(Value::keyword(&s)),
750
751 Token::LeftParen | Token::LeftBracket => self.parse_list(start_pos),
753
754 Token::VectorStart => self.parse_vector(start_pos),
756
757 Token::Quote => {
759 let quoted = self.parse_expr()?;
760 Ok(Value::cons(Value::symbol("quote"), Value::cons(quoted, Value::Nil)))
761 }
762
763 Token::Quasiquote => {
765 let quoted = self.parse_expr()?;
766 Ok(Value::cons(
767 Value::symbol("quasiquote"),
768 Value::cons(quoted, Value::Nil),
769 ))
770 }
771
772 Token::Unquote => {
774 let quoted = self.parse_expr()?;
775 Ok(Value::cons(
776 Value::symbol("unquote"),
777 Value::cons(quoted, Value::Nil),
778 ))
779 }
780
781 Token::UnquoteSplicing => {
783 let quoted = self.parse_expr()?;
784 Ok(Value::cons(
785 Value::symbol("unquote-splicing"),
786 Value::cons(quoted, Value::Nil),
787 ))
788 }
789
790 Token::RightParen | Token::RightBracket => Err(ParseError::new(
792 format!("Unexpected closing delimiter: {}", tok),
793 start_pos,
794 )),
795
796 Token::Dot => Err(ParseError::new(
797 "Unexpected dot outside of list".to_string(),
798 start_pos,
799 )),
800
801 Token::Eof => Err(ParseError::new(
802 "Unexpected end of input".to_string(),
803 start_pos,
804 )),
805 }
806 }
807
808 fn parse_list(&mut self, start_pos: Position) -> ParseResult<Value> {
810 let mut elements = Vec::new();
811 let mut dotted_tail = None;
812
813 loop {
814 let tok = self.tokenizer.peek_token()?;
815
816 match tok {
817 Token::RightParen | Token::RightBracket => {
818 self.tokenizer.next_token()?; break;
820 }
821
822 Token::Dot => {
823 self.tokenizer.next_token()?; dotted_tail = Some(self.parse_expr()?);
827
828 let tok = self.tokenizer.next_token()?;
830 if !matches!(tok, Token::RightParen | Token::RightBracket) {
831 return Err(ParseError::new(
832 format!("Expected ) after dotted tail, got {}", tok),
833 start_pos,
834 ));
835 }
836 break;
837 }
838
839 Token::Eof => {
840 return Err(ParseError::new(
841 "Unexpected EOF in list".to_string(),
842 start_pos,
843 ))
844 }
845
846 _ => {
847 elements.push(self.parse_expr()?);
848 }
849 }
850 }
851
852 let mut result = dotted_tail.unwrap_or(Value::Nil);
854 for elem in elements.into_iter().rev() {
855 result = Value::cons(elem, result);
856 }
857
858 Ok(result)
859 }
860
861 fn parse_vector(&mut self, start_pos: Position) -> ParseResult<Value> {
863 let mut elements = Vec::new();
864
865 loop {
866 let tok = self.tokenizer.peek_token()?;
867
868 match tok {
869 Token::RightParen => {
870 self.tokenizer.next_token()?; break;
872 }
873
874 Token::Eof => {
875 return Err(ParseError::new(
876 "Unexpected EOF in vector".to_string(),
877 start_pos,
878 ))
879 }
880
881 _ => {
882 elements.push(self.parse_expr()?);
883 }
884 }
885 }
886
887 Ok(Value::vector(elements))
888 }
889}
890
891#[cfg(test)]
896mod tests {
897 use super::*;
898
899 #[test]
900 fn test_tokenize_simple() {
901 let mut tok = Tokenizer::new("(+ 1 2)");
902 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
903 assert_eq!(tok.next_token().unwrap(), Token::Symbol("+".to_string()));
904 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
905 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
906 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
907 assert_eq!(tok.next_token().unwrap(), Token::Eof);
908 }
909
910 #[test]
911 fn test_tokenize_whitespace_agnostic() {
912 let input = r#"(let ((x 1)
914 (y 2))
915 (+ x y))"#;
916 let mut tok = Tokenizer::new(input);
917
918 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
919 assert_eq!(tok.next_token().unwrap(), Token::Symbol("let".to_string()));
920 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
921 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
922 assert_eq!(tok.next_token().unwrap(), Token::Symbol("x".to_string()));
923 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
924 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
925 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
927 assert_eq!(tok.next_token().unwrap(), Token::Symbol("y".to_string()));
928 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
929 }
930
931 #[test]
932 fn test_tokenize_strings() {
933 let mut tok = Tokenizer::new(r#""hello world""#);
934 assert_eq!(
935 tok.next_token().unwrap(),
936 Token::String("hello world".to_string())
937 );
938
939 let mut tok = Tokenizer::new(r#""with\nnewline""#);
940 assert_eq!(
941 tok.next_token().unwrap(),
942 Token::String("with\nnewline".to_string())
943 );
944 }
945
946 #[test]
947 fn test_tokenize_comments() {
948 let mut tok = Tokenizer::new("(+ 1 ; comment\n 2)");
949 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
950 assert_eq!(tok.next_token().unwrap(), Token::Symbol("+".to_string()));
951 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
952 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
954 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
955 }
956
957 #[test]
958 fn test_tokenize_block_comments() {
959 let mut tok = Tokenizer::new("(+ 1 #| block comment |# 2)");
960 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
961 assert_eq!(tok.next_token().unwrap(), Token::Symbol("+".to_string()));
962 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
963 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
965 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
966 }
967
968 #[test]
969 fn test_tokenize_booleans() {
970 let mut tok = Tokenizer::new("#t #f");
971 assert_eq!(tok.next_token().unwrap(), Token::Bool(true));
972 assert_eq!(tok.next_token().unwrap(), Token::Bool(false));
973 }
974
975 #[test]
976 fn test_tokenize_characters() {
977 let mut tok = Tokenizer::new(r#"#\a #\space #\newline"#);
978 assert_eq!(tok.next_token().unwrap(), Token::Char('a'));
979 assert_eq!(tok.next_token().unwrap(), Token::Char(' '));
980 assert_eq!(tok.next_token().unwrap(), Token::Char('\n'));
981 }
982
983 #[test]
984 fn test_tokenize_hex_numbers() {
985 let mut tok = Tokenizer::new("#xff");
987 assert_eq!(tok.next_token().unwrap(), Token::Integer(255));
988
989 let mut tok = Tokenizer::new("#X10");
991 assert_eq!(tok.next_token().unwrap(), Token::Integer(16));
992
993 let mut tok = Tokenizer::new("#xDEADBEEF");
995 assert_eq!(tok.next_token().unwrap(), Token::Integer(0xDEADBEEF));
996
997 let mut tok = Tokenizer::new("#x0");
999 assert_eq!(tok.next_token().unwrap(), Token::Integer(0));
1000 }
1001
1002 #[test]
1003 fn test_tokenize_octal_numbers() {
1004 let mut tok = Tokenizer::new("#o77");
1006 assert_eq!(tok.next_token().unwrap(), Token::Integer(63));
1007
1008 let mut tok = Tokenizer::new("#O10");
1010 assert_eq!(tok.next_token().unwrap(), Token::Integer(8));
1011
1012 let mut tok = Tokenizer::new("#o0");
1014 assert_eq!(tok.next_token().unwrap(), Token::Integer(0));
1015
1016 let mut tok = Tokenizer::new("#o777");
1018 assert_eq!(tok.next_token().unwrap(), Token::Integer(511));
1019 }
1020
1021 #[test]
1022 fn test_tokenize_binary_numbers() {
1023 let mut tok = Tokenizer::new("#b1010");
1025 assert_eq!(tok.next_token().unwrap(), Token::Integer(10));
1026
1027 let mut tok = Tokenizer::new("#B1111");
1029 assert_eq!(tok.next_token().unwrap(), Token::Integer(15));
1030
1031 let mut tok = Tokenizer::new("#b0");
1033 assert_eq!(tok.next_token().unwrap(), Token::Integer(0));
1034
1035 let mut tok = Tokenizer::new("#b11111111");
1037 assert_eq!(tok.next_token().unwrap(), Token::Integer(255));
1038 }
1039
1040 #[test]
1041 fn test_tokenize_quote() {
1042 let mut tok = Tokenizer::new("'(1 2)");
1043 assert_eq!(tok.next_token().unwrap(), Token::Quote);
1044 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
1045 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
1046 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
1047 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
1048 }
1049
1050 #[test]
1051 fn test_error_positions() {
1052 let mut tok = Tokenizer::new("(+ 1\n \"unclosed string");
1053 tok.next_token().unwrap(); tok.next_token().unwrap(); tok.next_token().unwrap(); let err = tok.next_token().unwrap_err();
1058 assert_eq!(err.position.line, 2); assert!(err.message.contains("EOF in string"));
1060 }
1061
1062 #[test]
1067 fn test_parse_integer() {
1068 let mut parser = Parser::new("42");
1069 let val = parser.parse().unwrap();
1070 assert!(val.is_integer());
1071 if let Value::Integer(n) = val {
1072 assert_eq!(n, 42);
1073 }
1074 }
1075
1076 #[test]
1077 fn test_parse_simple_list() {
1078 let mut parser = Parser::new("(+ 1 2)");
1079 let val = parser.parse().unwrap();
1080 assert!(val.is_list());
1081
1082 if let Value::Pair(ref p) = val {
1084 let pair = p.borrow();
1085 assert!(pair.car.is_symbol());
1086 }
1087 }
1088
1089 #[test]
1090 fn test_parse_nested_list() {
1091 let mut parser = Parser::new("(+ (* 2 3) 4)");
1092 let val = parser.parse().unwrap();
1093 assert!(val.is_list());
1094 }
1095
1096 #[test]
1097 fn test_parse_quoted() {
1098 let mut parser = Parser::new("'(1 2 3)");
1099 let val = parser.parse().unwrap();
1100
1101 if let Value::Pair(ref p) = val {
1103 let pair = p.borrow();
1104 if let Value::Symbol(s) = &pair.car {
1105 assert_eq!(&**s, "quote");
1106 } else {
1107 panic!("Expected symbol 'quote'");
1108 }
1109 } else {
1110 panic!("Expected pair");
1111 }
1112 }
1113
1114 #[test]
1115 fn test_parse_vector() {
1116 let mut parser = Parser::new("#(1 2 3)");
1117 let val = parser.parse().unwrap();
1118 assert!(val.is_vector());
1119
1120 if let Value::Vector(ref v) = val {
1121 let vec = v.borrow();
1122 assert_eq!(vec.len(), 3);
1123 }
1124 }
1125
1126 #[test]
1127 fn test_parse_dotted_list() {
1128 let mut parser = Parser::new("(1 . 2)");
1129 let val = parser.parse().unwrap();
1130
1131 if let Value::Pair(ref p) = val {
1132 let pair = p.borrow();
1133 assert!(matches!(pair.car, Value::Integer(1)));
1134 assert!(matches!(pair.cdr, Value::Integer(2)));
1135 } else {
1136 panic!("Expected pair");
1137 }
1138 }
1139
1140 #[test]
1141 fn test_parse_string() {
1142 let mut parser = Parser::new(r#""hello world""#);
1143 let val = parser.parse().unwrap();
1144 assert!(val.is_string());
1145 }
1146
1147 #[test]
1148 fn test_parse_bool() {
1149 let mut parser = Parser::new("#t");
1150 let val = parser.parse().unwrap();
1151 assert!(val.is_bool());
1152 assert!(val.is_true());
1153
1154 let mut parser = Parser::new("#f");
1155 let val = parser.parse().unwrap();
1156 assert!(val.is_bool());
1157 assert!(!val.is_true());
1158 }
1159
1160 #[test]
1161 fn test_parse_multiline_let() {
1162 let input = r#"
1164 (let ((x 1)
1165 (y 2))
1166 (+ x y))
1167 "#;
1168
1169 let mut parser = Parser::new(input);
1170 let val = parser.parse().unwrap();
1171 assert!(val.is_list());
1172
1173 }
1176
1177 #[test]
1178 fn test_parse_all() {
1179 let input = "(define x 1) (define y 2) (+ x y)";
1180 let mut parser = Parser::new(input);
1181 let exprs = parser.parse_all().unwrap();
1182 assert_eq!(exprs.len(), 3);
1183 }
1184
1185 #[test]
1186 fn test_parse_empty_list() {
1187 let mut parser = Parser::new("()");
1188 let val = parser.parse().unwrap();
1189 assert!(val.is_nil());
1190 }
1191
1192 #[test]
1193 fn test_parse_keyword() {
1194 let mut parser = Parser::new("#:foo");
1195 let val = parser.parse().unwrap();
1196 if let Value::Keyword(ref k) = val {
1197 assert_eq!(&**k, "foo");
1198 } else {
1199 panic!("Expected keyword");
1200 }
1201 }
1202}
1203