better function calls + cleanup
This commit is contained in:
parent
6049299cab
commit
c9a404a5f9
31
src/lexer.rs
31
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<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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue