From 8aeb6e543e0160b770e65d8870cc0d077d12ff73 Mon Sep 17 00:00:00 2001 From: Raptorox <70806316+Raptorox@users.noreply.github.com> Date: Tue, 16 Jun 2026 23:37:18 +0200 Subject: [PATCH] added ParseResult --- src/error.rs | 20 +++++++++++++++++++ src/main.rs | 3 ++- src/parser.rs | 55 +++++++++++++++++++++++++++++++-------------------- 3 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 src/error.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..36e4d9e --- /dev/null +++ b/src/error.rs @@ -0,0 +1,20 @@ +use std::{error::Error, fmt::Display}; + +#[derive(Debug)] +pub struct ParseError { + message: String +} + +impl ParseError { + pub fn new(message: impl Into) -> Self { + Self { message: message.into() } + } +} + +impl Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "parse error: {}", self.message) + } +} + +impl Error for ParseError {} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f0cd919..9405cc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use std::{fs::File, io::Read}; mod token; mod expr; mod lexer; +mod error; use lexer::Lexer; mod parser; use parser::Parser; @@ -29,7 +30,7 @@ fn main() -> std::io::Result<()> { let mut parser = Parser::new(tokens); loop { - let parsed = parser.parse(); + let parsed = parser.parse().unwrap_or(expr::Expr::EOL); match parsed { expr::Expr::EOL => break, _ => { diff --git a/src/parser.rs b/src/parser.rs index 3afc6e0..181b4fa 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,8 @@ use crate::token::Token; use crate::expr::{Expr, UnaryOp, BinaryOp, infix_bp, prefix_bp}; +use crate::error::ParseError; + +type ParseResult = Result; pub struct Parser { tokens: Vec, @@ -28,39 +31,49 @@ impl Parser { tok } - fn parse_atom(&mut self) -> Expr { + fn expect(&mut self, expected: &Token) -> ParseResult { match self.next() { - Some(Token::Number(n)) => Expr::Number(n), - Some(Token::Ident(id)) => Expr::Ident(id), - Some(Token::LParen) => { - let expr = self.parse_expr(0); - - match self.next() { - Some(Token::RParen) => expr, - _ => panic!("expected ')'") - } - }, - tok => panic!("unknown token: {tok:?}") + Some(tok) if &tok == expected => Ok(tok), + other => Err(ParseError::new(format!( + "expected {expected:?}, got {other:?}" + ))) } } - fn parse_prefix(&mut self) -> Expr { + fn parse_atom(&mut self) -> ParseResult { + match self.next() { + Some(Token::Number(n)) => Ok(Expr::Number(n)), + Some(Token::Ident(id)) => Ok(Expr::Ident(id)), + Some(Token::LParen) => { + let expr = self.parse_expr(0)?; + + self.expect(&Token::RParen)?; + + Ok(expr) + }, + tok => Err(ParseError::new(format!( + "unexpected token: {tok:?}" + ))) + } + } + + fn parse_prefix(&mut self) -> ParseResult { match self.peek() { Some(Token::Minus) => { self.advance(); let op = UnaryOp::Neg; let bp = prefix_bp(&op); - let rhs = self.parse_expr(bp); + let rhs = self.parse_expr(bp)?; - Expr::Unary { op, right: Box::new(rhs) } + Ok(Expr::Unary { op, right: Box::new(rhs) }) }, _ => self.parse_atom() } } - fn parse_expr(&mut self, min_bp: u8) -> Expr { - let mut lhs = self.parse_prefix(); + fn parse_expr(&mut self, min_bp: u8) -> ParseResult { + let mut lhs = self.parse_prefix()?; loop { let op = match self.peek() { @@ -81,16 +94,16 @@ impl Parser { self.advance(); - let rhs = self.parse_expr(right_bp); + let rhs = self.parse_expr(right_bp)?; lhs = Expr::Binary { left: Box::new(lhs), op, right: Box::new(rhs) } } - lhs + Ok(lhs) } - pub fn parse(&mut self) -> Expr { - if self.peek().is_none() {return Expr::EOL} + pub fn parse(&mut self) -> ParseResult { + if self.peek().is_none() {return Ok(Expr::EOL)} self.parse_expr(0) } } \ No newline at end of file