better function calls + cleanup
This commit is contained in:
parent
6049299cab
commit
c9a404a5f9
29
src/lexer.rs
29
src/lexer.rs
|
@ -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 {
|
||||||
|
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"),
|
||||||
}
|
}
|
||||||
impl Check for Option<char> {
|
|
||||||
fn check(self) -> Result<char> {
|
|
||||||
self.ok_or(LexError::UnexpectedEnd)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue