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),
}
#[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<char>;
}
impl Check for Option<char> {
fn check(self) -> Result<char> {
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<char> {
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<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) {
self.next();
}
fn eat_to(&mut self, tk: Token) -> Option<Result<Token>> {
self.eat();
Some(Ok(tk))
}
fn eat_peek(&mut self) -> Option<char> {
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));

View File

@ -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<LexError> 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<T> = std::result::Result<T, ParseError>;
@ -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;
}