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
672 if sym.ends_with(':') {
674 let keyword_name = sym[..sym.len()-1].to_string();
675 Ok(Token::Keyword(keyword_name))
676 } else {
677 Ok(Token::Symbol(sym))
678 }
679 }
680 }
681 }
682
683 pub fn peek_token(&mut self) -> ParseResult<&Token> {
685 if self.peeked.is_none() {
686 let tok = self.next_token()?;
687 self.peeked = Some(tok);
688 }
689 Ok(self.peeked.as_ref().unwrap())
690 }
691}
692
693pub struct Parser {
708 tokenizer: Tokenizer,
709}
710
711impl Parser {
712 pub fn new(input: &str) -> Self {
714 Parser {
715 tokenizer: Tokenizer::new(input),
716 }
717 }
718
719 pub fn parse(&mut self) -> ParseResult<Value> {
723 self.parse_expr()
724 }
725
726 pub fn parse_all(&mut self) -> ParseResult<Vec<Value>> {
730 let mut exprs = Vec::new();
731
732 loop {
733 let tok = self.tokenizer.peek_token()?;
734 if *tok == Token::Eof {
735 break;
736 }
737 exprs.push(self.parse_expr()?);
738 }
739
740 Ok(exprs)
741 }
742
743 fn parse_expr(&mut self) -> ParseResult<Value> {
745 let start_pos = self.tokenizer.position();
746 let tok = self.tokenizer.next_token()?;
747
748 match tok {
749 Token::Integer(n) => Ok(Value::integer(n)),
751 Token::Real(n) => Ok(Value::real(n)),
752 Token::String(s) => Ok(Value::string(s)),
753 Token::Char(ch) => Ok(Value::char(ch)),
754 Token::Bool(b) => Ok(Value::bool(b)),
755 Token::Symbol(s) => Ok(Value::symbol(&s)),
756 Token::Keyword(s) => Ok(Value::keyword(&s)),
757
758 Token::LeftParen | Token::LeftBracket => self.parse_list(start_pos),
760
761 Token::VectorStart => self.parse_vector(start_pos),
763
764 Token::Quote => {
766 let quoted = self.parse_expr()?;
767 Ok(Value::cons(Value::symbol("quote"), Value::cons(quoted, Value::Nil)))
768 }
769
770 Token::Quasiquote => {
772 let quoted = self.parse_expr()?;
773 Ok(Value::cons(
774 Value::symbol("quasiquote"),
775 Value::cons(quoted, Value::Nil),
776 ))
777 }
778
779 Token::Unquote => {
781 let quoted = self.parse_expr()?;
782 Ok(Value::cons(
783 Value::symbol("unquote"),
784 Value::cons(quoted, Value::Nil),
785 ))
786 }
787
788 Token::UnquoteSplicing => {
790 let quoted = self.parse_expr()?;
791 Ok(Value::cons(
792 Value::symbol("unquote-splicing"),
793 Value::cons(quoted, Value::Nil),
794 ))
795 }
796
797 Token::RightParen | Token::RightBracket => Err(ParseError::new(
799 format!("Unexpected closing delimiter: {}", tok),
800 start_pos,
801 )),
802
803 Token::Dot => Err(ParseError::new(
804 "Unexpected dot outside of list".to_string(),
805 start_pos,
806 )),
807
808 Token::Eof => Err(ParseError::new(
809 "Unexpected end of input".to_string(),
810 start_pos,
811 )),
812 }
813 }
814
815 fn parse_list(&mut self, start_pos: Position) -> ParseResult<Value> {
817 let mut elements = Vec::new();
818 let mut dotted_tail = None;
819
820 loop {
821 let tok = self.tokenizer.peek_token()?;
822
823 match tok {
824 Token::RightParen | Token::RightBracket => {
825 self.tokenizer.next_token()?; break;
827 }
828
829 Token::Dot => {
830 self.tokenizer.next_token()?; dotted_tail = Some(self.parse_expr()?);
834
835 let tok = self.tokenizer.next_token()?;
837 if !matches!(tok, Token::RightParen | Token::RightBracket) {
838 return Err(ParseError::new(
839 format!("Expected ) after dotted tail, got {}", tok),
840 start_pos,
841 ));
842 }
843 break;
844 }
845
846 Token::Eof => {
847 return Err(ParseError::new(
848 "Unexpected EOF in list".to_string(),
849 start_pos,
850 ))
851 }
852
853 _ => {
854 elements.push(self.parse_expr()?);
855 }
856 }
857 }
858
859 let mut result = dotted_tail.unwrap_or(Value::Nil);
861 for elem in elements.into_iter().rev() {
862 result = Value::cons(elem, result);
863 }
864
865 Ok(result)
866 }
867
868 fn parse_vector(&mut self, start_pos: Position) -> ParseResult<Value> {
870 let mut elements = Vec::new();
871
872 loop {
873 let tok = self.tokenizer.peek_token()?;
874
875 match tok {
876 Token::RightParen => {
877 self.tokenizer.next_token()?; break;
879 }
880
881 Token::Eof => {
882 return Err(ParseError::new(
883 "Unexpected EOF in vector".to_string(),
884 start_pos,
885 ))
886 }
887
888 _ => {
889 elements.push(self.parse_expr()?);
890 }
891 }
892 }
893
894 Ok(Value::vector(elements))
895 }
896}
897
898#[cfg(test)]
903mod tests {
904 use super::*;
905
906 #[test]
907 fn test_tokenize_simple() {
908 let mut tok = Tokenizer::new("(+ 1 2)");
909 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
910 assert_eq!(tok.next_token().unwrap(), Token::Symbol("+".to_string()));
911 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
912 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
913 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
914 assert_eq!(tok.next_token().unwrap(), Token::Eof);
915 }
916
917 #[test]
918 fn test_tokenize_whitespace_agnostic() {
919 let input = r#"(let ((x 1)
921 (y 2))
922 (+ x y))"#;
923 let mut tok = Tokenizer::new(input);
924
925 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
926 assert_eq!(tok.next_token().unwrap(), Token::Symbol("let".to_string()));
927 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
928 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
929 assert_eq!(tok.next_token().unwrap(), Token::Symbol("x".to_string()));
930 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
931 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
932 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
934 assert_eq!(tok.next_token().unwrap(), Token::Symbol("y".to_string()));
935 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
936 }
937
938 #[test]
939 fn test_tokenize_strings() {
940 let mut tok = Tokenizer::new(r#""hello world""#);
941 assert_eq!(
942 tok.next_token().unwrap(),
943 Token::String("hello world".to_string())
944 );
945
946 let mut tok = Tokenizer::new(r#""with\nnewline""#);
947 assert_eq!(
948 tok.next_token().unwrap(),
949 Token::String("with\nnewline".to_string())
950 );
951 }
952
953 #[test]
954 fn test_tokenize_comments() {
955 let mut tok = Tokenizer::new("(+ 1 ; comment\n 2)");
956 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
957 assert_eq!(tok.next_token().unwrap(), Token::Symbol("+".to_string()));
958 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
959 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
961 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
962 }
963
964 #[test]
965 fn test_tokenize_block_comments() {
966 let mut tok = Tokenizer::new("(+ 1 #| block comment |# 2)");
967 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
968 assert_eq!(tok.next_token().unwrap(), Token::Symbol("+".to_string()));
969 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
970 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
972 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
973 }
974
975 #[test]
976 fn test_tokenize_booleans() {
977 let mut tok = Tokenizer::new("#t #f");
978 assert_eq!(tok.next_token().unwrap(), Token::Bool(true));
979 assert_eq!(tok.next_token().unwrap(), Token::Bool(false));
980 }
981
982 #[test]
983 fn test_tokenize_characters() {
984 let mut tok = Tokenizer::new(r#"#\a #\space #\newline"#);
985 assert_eq!(tok.next_token().unwrap(), Token::Char('a'));
986 assert_eq!(tok.next_token().unwrap(), Token::Char(' '));
987 assert_eq!(tok.next_token().unwrap(), Token::Char('\n'));
988 }
989
990 #[test]
991 fn test_tokenize_hex_numbers() {
992 let mut tok = Tokenizer::new("#xff");
994 assert_eq!(tok.next_token().unwrap(), Token::Integer(255));
995
996 let mut tok = Tokenizer::new("#X10");
998 assert_eq!(tok.next_token().unwrap(), Token::Integer(16));
999
1000 let mut tok = Tokenizer::new("#xDEADBEEF");
1002 assert_eq!(tok.next_token().unwrap(), Token::Integer(0xDEADBEEF));
1003
1004 let mut tok = Tokenizer::new("#x0");
1006 assert_eq!(tok.next_token().unwrap(), Token::Integer(0));
1007 }
1008
1009 #[test]
1010 fn test_tokenize_octal_numbers() {
1011 let mut tok = Tokenizer::new("#o77");
1013 assert_eq!(tok.next_token().unwrap(), Token::Integer(63));
1014
1015 let mut tok = Tokenizer::new("#O10");
1017 assert_eq!(tok.next_token().unwrap(), Token::Integer(8));
1018
1019 let mut tok = Tokenizer::new("#o0");
1021 assert_eq!(tok.next_token().unwrap(), Token::Integer(0));
1022
1023 let mut tok = Tokenizer::new("#o777");
1025 assert_eq!(tok.next_token().unwrap(), Token::Integer(511));
1026 }
1027
1028 #[test]
1029 fn test_tokenize_binary_numbers() {
1030 let mut tok = Tokenizer::new("#b1010");
1032 assert_eq!(tok.next_token().unwrap(), Token::Integer(10));
1033
1034 let mut tok = Tokenizer::new("#B1111");
1036 assert_eq!(tok.next_token().unwrap(), Token::Integer(15));
1037
1038 let mut tok = Tokenizer::new("#b0");
1040 assert_eq!(tok.next_token().unwrap(), Token::Integer(0));
1041
1042 let mut tok = Tokenizer::new("#b11111111");
1044 assert_eq!(tok.next_token().unwrap(), Token::Integer(255));
1045 }
1046
1047 #[test]
1048 fn test_tokenize_quote() {
1049 let mut tok = Tokenizer::new("'(1 2)");
1050 assert_eq!(tok.next_token().unwrap(), Token::Quote);
1051 assert_eq!(tok.next_token().unwrap(), Token::LeftParen);
1052 assert_eq!(tok.next_token().unwrap(), Token::Integer(1));
1053 assert_eq!(tok.next_token().unwrap(), Token::Integer(2));
1054 assert_eq!(tok.next_token().unwrap(), Token::RightParen);
1055 }
1056
1057 #[test]
1058 fn test_error_positions() {
1059 let mut tok = Tokenizer::new("(+ 1\n \"unclosed string");
1060 tok.next_token().unwrap(); tok.next_token().unwrap(); tok.next_token().unwrap(); let err = tok.next_token().unwrap_err();
1065 assert_eq!(err.position.line, 2); assert!(err.message.contains("EOF in string"));
1067 }
1068
1069 #[test]
1074 fn test_parse_integer() {
1075 let mut parser = Parser::new("42");
1076 let val = parser.parse().unwrap();
1077 assert!(val.is_integer());
1078 if let Value::Integer(n) = val {
1079 assert_eq!(n, 42);
1080 }
1081 }
1082
1083 #[test]
1084 fn test_parse_simple_list() {
1085 let mut parser = Parser::new("(+ 1 2)");
1086 let val = parser.parse().unwrap();
1087 assert!(val.is_list());
1088
1089 if let Value::Pair(ref p) = val {
1091 let pair = p.borrow();
1092 assert!(pair.car.is_symbol());
1093 }
1094 }
1095
1096 #[test]
1097 fn test_parse_nested_list() {
1098 let mut parser = Parser::new("(+ (* 2 3) 4)");
1099 let val = parser.parse().unwrap();
1100 assert!(val.is_list());
1101 }
1102
1103 #[test]
1104 fn test_parse_quoted() {
1105 let mut parser = Parser::new("'(1 2 3)");
1106 let val = parser.parse().unwrap();
1107
1108 if let Value::Pair(ref p) = val {
1110 let pair = p.borrow();
1111 if let Value::Symbol(s) = &pair.car {
1112 assert_eq!(&**s, "quote");
1113 } else {
1114 panic!("Expected symbol 'quote'");
1115 }
1116 } else {
1117 panic!("Expected pair");
1118 }
1119 }
1120
1121 #[test]
1122 fn test_parse_vector() {
1123 let mut parser = Parser::new("#(1 2 3)");
1124 let val = parser.parse().unwrap();
1125 assert!(val.is_vector());
1126
1127 if let Value::Vector(ref v) = val {
1128 let vec = v.borrow();
1129 assert_eq!(vec.len(), 3);
1130 }
1131 }
1132
1133 #[test]
1134 fn test_parse_dotted_list() {
1135 let mut parser = Parser::new("(1 . 2)");
1136 let val = parser.parse().unwrap();
1137
1138 if let Value::Pair(ref p) = val {
1139 let pair = p.borrow();
1140 assert!(matches!(pair.car, Value::Integer(1)));
1141 assert!(matches!(pair.cdr, Value::Integer(2)));
1142 } else {
1143 panic!("Expected pair");
1144 }
1145 }
1146
1147 #[test]
1148 fn test_parse_string() {
1149 let mut parser = Parser::new(r#""hello world""#);
1150 let val = parser.parse().unwrap();
1151 assert!(val.is_string());
1152 }
1153
1154 #[test]
1155 fn test_parse_bool() {
1156 let mut parser = Parser::new("#t");
1157 let val = parser.parse().unwrap();
1158 assert!(val.is_bool());
1159 assert!(val.is_true());
1160
1161 let mut parser = Parser::new("#f");
1162 let val = parser.parse().unwrap();
1163 assert!(val.is_bool());
1164 assert!(!val.is_true());
1165 }
1166
1167 #[test]
1168 fn test_parse_multiline_let() {
1169 let input = r#"
1171 (let ((x 1)
1172 (y 2))
1173 (+ x y))
1174 "#;
1175
1176 let mut parser = Parser::new(input);
1177 let val = parser.parse().unwrap();
1178 assert!(val.is_list());
1179
1180 }
1183
1184 #[test]
1185 fn test_parse_all() {
1186 let input = "(define x 1) (define y 2) (+ x y)";
1187 let mut parser = Parser::new(input);
1188 let exprs = parser.parse_all().unwrap();
1189 assert_eq!(exprs.len(), 3);
1190 }
1191
1192 #[test]
1193 fn test_parse_empty_list() {
1194 let mut parser = Parser::new("()");
1195 let val = parser.parse().unwrap();
1196 assert!(val.is_nil());
1197 }
1198
1199 #[test]
1200 fn test_parse_keyword() {
1201 let mut parser = Parser::new("#:foo");
1202 let val = parser.parse().unwrap();
1203 if let Value::Keyword(ref k) = val {
1204 assert_eq!(&**k, "foo");
1205 } else {
1206 panic!("Expected keyword");
1207 }
1208 }
1209}
1210