From c9a404a5f9df2ac39b530b3bf593c88c9052a122 Mon Sep 17 00:00:00 2001 From: minish Date: Tue, 1 Jul 2025 19:56:45 -0400 Subject: [PATCH] better function calls + cleanup --- src/lexer.rs | 31 ++++++++++++++++++------------- src/parser.rs | 25 ++++++++++++++++++++----- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/lexer.rs b/src/lexer.rs index b044c02..c04dac7 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -63,7 +63,7 @@ pub enum Token { Literal(Literal), } -#[derive(PartialEq, Eq, PartialOrd, Ord)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum Precedence { Min, Return, @@ -112,12 +112,13 @@ pub enum LexError { UnexpectedCharacter(char), UnexpectedEnd, } -trait Check { - fn check(self) -> Result; -} -impl Check for Option { - fn check(self) -> Result { - self.ok_or(LexError::UnexpectedEnd) +impl fmt::Display for LexError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::UnexpectedEnd => write!(f, "unexpected end of source"), + Self::UnexpectedCharacter(c) => write!(f, "unexpected char '{c}'"), + Self::InvalidEscape(c) => write!(f, "\"\\{c}\" is not a valid string escape"), + } } } @@ -146,7 +147,6 @@ where fn next(&mut self) -> Option { self.chars.next() } - fn next_unwrap(&mut self) -> char { match self.next() { Some(c) => c, @@ -154,15 +154,20 @@ where } } + fn try_peek(&mut self) -> Result { + self.peek().ok_or(LexError::UnexpectedEnd) + } + fn try_eat_peek(&mut self) -> Result { + self.eat_peek().ok_or(LexError::UnexpectedEnd) + } + fn eat(&mut self) { self.next(); } - fn eat_to(&mut self, tk: Token) -> Option> { self.eat(); Some(Ok(tk)) } - fn eat_peek(&mut self) -> Option { self.eat(); self.peek() @@ -216,11 +221,11 @@ where let mut str = String::new(); loop { - match self.peek().check()? { - '\\' => match self.eat_peek().check()? { + match self.try_peek()? { + '\\' => match self.try_eat_peek()? { 'n' => { self.eat(); - str.push('\n') + str.push('\n'); } c => { break Err(LexError::InvalidEscape(c)); diff --git a/src/parser.rs b/src/parser.rs index 7bddd2f..f2e118b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,4 @@ -use std::iter::Peekable; +use std::{fmt, iter::Peekable}; use crate::lexer::{Associativity, LexError, Literal, Precedence, Token}; @@ -51,6 +51,15 @@ impl From for ParseError { Self::LexError(err) } } +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::UnexpectedEnd => write!(f, "unexpected end of token stream"), + Self::UnexpectedToken(t) => write!(f, "unexpected token: {t:?}"), + Self::LexError(err) => write!(f, "error while lexing: {err}"), + } + } +} pub type Result = std::result::Result; @@ -109,10 +118,6 @@ where _ => unreachable!(), }) } - // return - Token::Return => Box::new(Expr::Return(self.parse_expr(Precedence::Min, false)?)), - // not - Token::Not => Box::new(Expr::Not(self.parse_expr(Precedence::Min, false)?)), // unexpected token t => return Err(ParseError::UnexpectedToken(t)), }; @@ -127,12 +132,22 @@ where Ok(Token::ParenOpen) => { // eat opening paren self.eat(); + let mut exprs = Vec::new(); while !matches!(self.try_peek()?, Token::ParenClose) { exprs.push(*self.parse_expr(Precedence::Min, false)?); + + // Continue if there is a comma, + // ignore closing parens + match self.try_peek()? { + Token::Comma => self.eat(), + Token::ParenClose => {} + _ => return Err(ParseError::UnexpectedToken(self.next_unwrap())), + } } // eat closing paren self.eat(); + lhs = Box::new(Expr::Call(lhs, exprs)); continue; }