use std::collections::HashMap; use crate::{ expr::Expr, token::{Token, TokenType}, }; pub struct Parser { tokens: Vec<Token>, current: usize, env: Vec<char>, } impl Parser { pub fn new(tokens: Vec<Token>) -> Self { Self { tokens, current: 0, env: vec![], } } pub fn parse(&mut self) -> Option<(HashMap<String, Expr>, Expr)> { let mut definitions = HashMap::new(); let mut main_expr = None; while !self.is_at_end() { let t = self.peek().token_type.clone(); match t { TokenType::DefinitionName(name) => { self.advance(); // consume definition name // function expr if self.peek().token_type != TokenType::Equals { self.print_error("Expected '=' after definition name"); return None; } self.advance(); // consume equals let definition = self.expr()?; if definitions.contains_key(&name) { self.print_error(&format!("Duplicate definition for ${}", name)); return None; } definitions.insert(name, definition); } // main expr _ => { let expr = self.expr()?; if main_expr.is_some() { self.print_error("Duplicate primary expression"); return None; } main_expr = Some(expr); } } } match main_expr { Some(expr) => Some((definitions, expr)), None => { self.print_error("Missing primary expression"); None } } } fn expr(&mut self) -> Option<Expr> { match &self.peek().token_type { TokenType::Lambda => self.abstraction(), TokenType::DefinitionName(name) => { let name = name.clone(); self.advance(); Some(Expr::DefinitionName(name)) } TokenType::LeftParen => self.application(), TokenType::Variable(c) => { let c = *c; self.advance(); Some(Expr::Var(self.find_variable(c)?)) } _ => { self.print_error( "Unexpected token. Expected one of 'λ', '/', '\\', '$', '(', or a variable", ); None } } } fn abstraction(&mut self) -> Option<Expr> { self.advance(); // consume lambda let mut abs_count = 0; while let TokenType::Variable(v) = self.peek().token_type { self.env.push(v); abs_count += 1; self.advance(); } if self.advance().token_type != TokenType::Period { self.print_error("Expected '.' after abstraction variable definitions"); return None; } let mut expr = self.expr()?; for _ in 0..abs_count { self.env.pop().unwrap(); expr = Expr::Lambda(Box::new(expr)); } Some(expr) } fn application(&mut self) -> Option<Expr> { self.advance(); // consume left paren let left = self.expr()?; let right = self.expr()?; dbg!(&left, &right); dbg!(&self.peek().token_type); if self.peek().token_type != TokenType::RightParen { self.print_error("Expected ')' after application"); return None; } self.advance(); // consume right paren Some(Expr::App(Box::new(left), Box::new(right))) } fn find_variable(&self, name: char) -> Option<usize> { let ret = self .env .iter() .enumerate() .find(|(_, x)| **x == name) .map(|(i, _)| i); match ret { Some(x) => Some(x), None => { self.print_error(&format!("Unknown variable '{}'.", name)); None } } } fn peek(&self) -> &Token { &self.tokens[self.current] } fn peek_next(&self) -> &TokenType { if self.current + 1 == self.tokens.len() { &TokenType::NoToken } else { &self.tokens[self.current + 1].token_type } } fn advance(&mut self) -> &Token { let t = &self.tokens[self.current]; self.current += 1; t } fn is_at_end(&self) -> bool { self.tokens.len() == self.current } fn print_error(&self, err: &str) { eprintln!("Error on line [{}]: {err}", self.peek().line); } }