use std::iter::Peekable; use std::ops::{Deref, RangeInclusive}; use std::usize; use std::vec::IntoIter; use super::ParseError; #[derive(Debug, PartialEq, Clone)] pub enum Token { LeftParen, RightParen, Symbol(String), } #[derive(Debug, PartialEq, Clone)] pub enum Sexpr { Symbol(String), List(Vec), } impl Sexpr { pub fn symbol(self) -> Option { match self { Sexpr::Symbol(item) => Some(item), _ => None, } } pub fn list(self) -> Option> { match self { Sexpr::List(item) => Some(item), _ => None, } } } fn tokenize(input: &str) -> Vec { let mut tokens = Vec::new(); // let mut chars = input.chars().peekable(); let mut chars = input.chars().peekable(); while let Some(c) = chars.next() { match c { '(' => tokens.push(Token::LeftParen), ')' => tokens.push(Token::RightParen), _ if c.is_whitespace() => (), _ => { let mut symbol = c.to_string(); while let Some(c) = chars.peek() { if c.is_whitespace() || *c == '(' || *c == ')' { break; } symbol.push(*c); chars.next(); } tokens.push(Token::Symbol(symbol)); } } } tokens } fn parse_expr(tokens: &mut Peekable>) -> Result { match tokens.next() { Some(Token::LeftParen) => { let mut list = Vec::new(); while !matches!(tokens.peek(), Some(Token::RightParen,)) { list.push(parse_expr(tokens)?); } let Some(Token::RightParen) = tokens.next() else { unreachable!() }; Ok(Sexpr::List(list)) } Some(Token::RightParen) => Err(ParseError::UnexpectedParenClose), Some(Token::Symbol(s)) => Ok(Sexpr::Symbol(s)), None => Err(ParseError::UnexpectedEof), } } fn parse(tokens: Vec) -> Result { let mut tokens = tokens.into_iter().peekable(); let ast = parse_expr(&mut tokens)?; if tokens.peek().is_some() { return Err(ParseError::TrailingTokens); }; Ok(ast) } pub fn parse_string(src: &str) -> Result { let tokens = tokenize(src); parse(tokens) }