From f898f3c3a17a7c71236cafff34f507b10d71f835 Mon Sep 17 00:00:00 2001 From: Tolmachev Igor Date: Sat, 9 May 2026 14:35:06 +0300 Subject: Replace todo!() in parser with errors --- compiler/src/ast/error.rs | 34 ++++++++++++++++-- compiler/src/ast/parser.rs | 86 +++++++++++++++++++--------------------------- 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/compiler/src/ast/error.rs b/compiler/src/ast/error.rs index 11f552d..ced2231 100644 --- a/compiler/src/ast/error.rs +++ b/compiler/src/ast/error.rs @@ -1,7 +1,37 @@ -use std::{error, fmt}; +use std::{ + error, fmt, + num::{ParseFloatError, ParseIntError}, + rc::Rc, +}; #[derive(Debug)] -pub enum Error {} +pub enum Error { + // Number + InvalidFloatLiteral(ParseFloatError), + InvalidIntegerLiteral(ParseIntError), + + // String + UnclosedString(Rc), + UnexpectedEscapeChar(char), + + // Par + UnexpectedRightPar, + UnclosedLeftPar, + + UnexpectedEof, +} + +impl From for Error { + fn from(value: ParseFloatError) -> Self { + Self::InvalidFloatLiteral(value) + } +} + +impl From for Error { + fn from(value: ParseIntError) -> Self { + Self::InvalidIntegerLiteral(value) + } +} impl fmt::Display for Error { fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { diff --git a/compiler/src/ast/parser.rs b/compiler/src/ast/parser.rs index 2e6d2dd..89a1280 100644 --- a/compiler/src/ast/parser.rs +++ b/compiler/src/ast/parser.rs @@ -1,4 +1,4 @@ -use std::{iter::Peekable, result}; +use std::iter::Peekable; use crate::{ ast::{Atom, Error, Expr, Program}, @@ -6,25 +6,19 @@ use crate::{ span::{Pos, Span, Spanned}, }; -type Result = result::Result>; - -fn parse_number(number: &str) -> Atom { +fn parse_number(number: &str) -> Result { let is_float = number.bytes().any(|b| matches!(b, b'.' | b'e' | b'E')); - if is_float { - match number.parse() { - Ok(ok) => Atom::Float(ok), - Err(err) => todo!("invalid float literal {number}: {err}"), - } + let atom = if is_float { + Atom::Float(number.parse()?) } else { - match number.parse() { - Ok(ok) => Atom::Integer(ok), - Err(err) => todo!("invalid integer literal {number}: {err}"), - } - } + Atom::Integer(number.parse()?) + }; + + Ok(atom) } -fn parse_string(string: &str) -> Atom { +fn parse_string(string: &str) -> Result { let mut result = String::new(); let mut is_escape = false; @@ -40,17 +34,17 @@ fn parse_string(string: &str) -> Atom { 'n' => result.push('\n'), '\\' => result.push('\\'), '\n' => {} - _ => todo!("unexpected escape char {ch:?}"), + _ => return Err(Error::UnexpectedEscapeChar(ch)), } is_escape = false; } } if is_escape { - todo!("unclosed string"); + return Err(Error::UnclosedString(string.into())); } - Atom::String(result.into()) + Ok(Atom::String(result.into())) } fn parse_symbol(symbol: &str) -> Atom { @@ -67,7 +61,7 @@ where I: Iterator>>, { tokens: Peekable, - last_token_end: Pos, + last_token_span: Span, } impl<'a, I> Parser<'a, I> @@ -77,7 +71,7 @@ where pub fn new(tokens: I) -> Self { Self { tokens: tokens.peekable(), - last_token_end: Pos::new(1, 0, 0), + last_token_span: Span::new(Pos::new(1, 0, 0), Pos::new(1, 0, 0)), } } @@ -88,75 +82,65 @@ where fn consume(&mut self) -> Option>> { self.tokens .next() - .inspect(|s| self.last_token_end = s.span.end) + .inspect(|s| self.last_token_span = s.span) } - fn parse_expr(&mut self) -> Result> { + fn parse_expr(&mut self) -> Result, Spanned> { let Spanned { inner: token, span } = match self.peek() { Some(spanned) => spanned, - None => todo!("unexpected eof"), + None => return Err(Spanned::new(Error::UnexpectedEof, self.last_token_span)), }; let expr = match token { Token::LeftPar => { self.consume(); - let list = self.parse_list()?; + let list = self.parse_list(span)?; let expr = if !list.is_empty() { Expr::List(list) } else { Expr::Atom(Atom::Nil) }; - Spanned::new(expr, Span::new(span.start, self.last_token_end)) + Spanned::new(expr, Span::new(span.start, self.last_token_span.end)) + } + Token::RightPar => { + self.consume(); + return Err(Spanned::new(Error::UnexpectedRightPar, span)); } - Token::RightPar => todo!("unexpected par"), Token::Quote => { self.consume(); - let quote = Spanned::new( - Expr::Atom(Atom::Symbol("quote".into())), - Span::new(span.start, self.last_token_end), - ); + let quote = Spanned::new(Expr::Atom(Atom::Symbol("quote".into())), span); let expr = self.parse_expr()?; - Spanned::new( Expr::List(vec![quote, expr]), - Span::new(span.start, self.last_token_end), + Span::new(span.start, self.last_token_span.end), ) } Token::Number(number) => { self.consume(); - - Spanned::new( - Expr::Atom(parse_number(number)), - Span::new(span.start, self.last_token_end), - ) + let atom = parse_number(number).map_err(|e| Spanned::new(e, span))?; + Spanned::new(Expr::Atom(atom), span) } Token::String(string) => { self.consume(); - - Spanned::new( - Expr::Atom(parse_string(string)), - Span::new(span.start, self.last_token_end), - ) + let atom = parse_string(string).map_err(|e| Spanned::new(e, span))?; + Spanned::new(Expr::Atom(atom), span) } Token::UnclosedString(string) => { self.consume(); - todo!("unclosed string {string:?}") + return Err(Spanned::new(Error::UnclosedString(string.into()), span)); } Token::Symbol(symbol) => { self.consume(); - - Spanned::new( - Expr::Atom(parse_symbol(symbol)), - Span::new(span.start, self.last_token_end), - ) + let atom = parse_symbol(symbol); + Spanned::new(Expr::Atom(atom), span) } }; Ok(expr) } - fn parse_list(&mut self) -> Result>> { + fn parse_list(&mut self, left_par_span: Span) -> Result>, Spanned> { let mut list = Vec::new(); while let Some(Spanned { inner: token, .. }) = self.peek() { @@ -169,10 +153,10 @@ where } } - todo!("unclosed par") + Err(Spanned::new(Error::UnclosedLeftPar, left_par_span)) } - pub fn parse(mut self) -> Result { + pub fn parse(mut self) -> Result> { let mut program = Vec::new(); while self.peek().is_some() { -- cgit v1.3