better function calls + cleanup

This commit is contained in:
minish 2025-07-01 19:56:45 -04:00
parent 6049299cab
commit c9a404a5f9
Signed by: min
SSH Key Fingerprint: SHA256:h4k7JNrfe1dzv1WE3oGVeAY9DPSZXIu3/j89+6DtHWE
2 changed files with 38 additions and 18 deletions

View File

@ -63,7 +63,7 @@ pub enum Token {
Literal(Literal), Literal(Literal),
} }
#[derive(PartialEq, Eq, PartialOrd, Ord)] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Precedence { pub enum Precedence {
Min, Min,
Return, Return,
@ -112,12 +112,13 @@ pub enum LexError {
UnexpectedCharacter(char), UnexpectedCharacter(char),
UnexpectedEnd, UnexpectedEnd,
} }
trait Check { impl fmt::Display for LexError {
fn check(self) -> Result<char>; fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
} match self {
impl Check for Option<char> { Self::UnexpectedEnd => write!(f, "unexpected end of source"),
fn check(self) -> Result<char> { Self::UnexpectedCharacter(c) => write!(f, "unexpected char '{c}'"),
self.ok_or(LexError::UnexpectedEnd) Self::InvalidEscape(c) => write!(f, "\"\\{c}\" is not a valid string escape"),
}
} }
} }
@ -146,7 +147,6 @@ where
fn next(&mut self) -> Option<char> { fn next(&mut self) -> Option<char> {
self.chars.next() self.chars.next()
} }
fn next_unwrap(&mut self) -> char { fn next_unwrap(&mut self) -> char {
match self.next() { match self.next() {
Some(c) => c, Some(c) => c,
@ -154,15 +154,20 @@ where
} }
} }
fn try_peek(&mut self) -> Result<char> {
self.peek().ok_or(LexError::UnexpectedEnd)
}
fn try_eat_peek(&mut self) -> Result<char> {
self.eat_peek().ok_or(LexError::UnexpectedEnd)
}
fn eat(&mut self) { fn eat(&mut self) {
self.next(); self.next();
} }
fn eat_to(&mut self, tk: Token) -> Option<Result<Token>> { fn eat_to(&mut self, tk: Token) -> Option<Result<Token>> {
self.eat(); self.eat();
Some(Ok(tk)) Some(Ok(tk))
} }
fn eat_peek(&mut self) -> Option<char> { fn eat_peek(&mut self) -> Option<char> {
self.eat(); self.eat();
self.peek() self.peek()
@ -216,11 +221,11 @@ where
let mut str = String::new(); let mut str = String::new();
loop { loop {
match self.peek().check()? { match self.try_peek()? {
'\\' => match self.eat_peek().check()? { '\\' => match self.try_eat_peek()? {
'n' => { 'n' => {
self.eat(); self.eat();
str.push('\n') str.push('\n');
} }
c => { c => {
break Err(LexError::InvalidEscape(c)); break Err(LexError::InvalidEscape(c));

View File

@ -1,4 +1,4 @@
use std::iter::Peekable; use std::{fmt, iter::Peekable};
use crate::lexer::{Associativity, LexError, Literal, Precedence, Token}; use crate::lexer::{Associativity, LexError, Literal, Precedence, Token};
@ -51,6 +51,15 @@ impl From<LexError> for ParseError {
Self::LexError(err) 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<T> = std::result::Result<T, ParseError>; pub type Result<T> = std::result::Result<T, ParseError>;
@ -109,10 +118,6 @@ where
_ => unreachable!(), _ => 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 // unexpected token
t => return Err(ParseError::UnexpectedToken(t)), t => return Err(ParseError::UnexpectedToken(t)),
}; };
@ -127,12 +132,22 @@ where
Ok(Token::ParenOpen) => { Ok(Token::ParenOpen) => {
// eat opening paren // eat opening paren
self.eat(); self.eat();
let mut exprs = Vec::new(); let mut exprs = Vec::new();
while !matches!(self.try_peek()?, Token::ParenClose) { while !matches!(self.try_peek()?, Token::ParenClose) {
exprs.push(*self.parse_expr(Precedence::Min, false)?); 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 // eat closing paren
self.eat(); self.eat();
lhs = Box::new(Expr::Call(lhs, exprs)); lhs = Box::new(Expr::Call(lhs, exprs));
continue; continue;
} }