diff --git a/bip/src/lib.rs b/bip/src/lib.rs index 66bf8ce..4ec4b95 100644 --- a/bip/src/lib.rs +++ b/bip/src/lib.rs @@ -13,6 +13,9 @@ pub enum ParseError { ExpectedParens, ExpectedSym, ExpectedTerm, + BadInt, + BadStr, + BadSym(char), } impl fmt::Display for ParseError { @@ -22,6 +25,9 @@ impl fmt::Display for ParseError { Self::ExpectedParens => write!(f, "expected parenthesis"), Self::ExpectedSym => write!(f, "expected symbol"), Self::ExpectedTerm => write!(f, "expected semicolon"), + Self::BadInt => write!(f, "invalid integer"), + Self::BadStr => write!(f, "unterminated string"), + Self::BadSym(c) => write!(f, "invalid symbol {c}"), } } } @@ -75,22 +81,22 @@ impl Symbol { fn take>( it: &mut Peekable, predicate: fn(c: char) -> bool, - ) -> Vec { + ) -> ParseResult> { let mut v = Vec::new(); while let Some(c) = it.peek() { if !predicate(*c) { - break; + return Ok(v); } v.push(*c); it.next(); } - v + Err(ParseError::Eof) } - pub fn parse(s: &str) -> Result, String> { + pub fn parse(s: &str) -> ParseResult> { let mut syms = Vec::new(); let mut it = s.chars().peekable(); @@ -109,7 +115,8 @@ impl Symbol { it.next(); } - let v = Symbol::take(&mut it, |c| c.is_numeric()); + let v = Symbol::take(&mut it, |c| c.is_numeric()) + .map_err(|_| ParseError::BadInt)?; if let Ok(n) = v.iter().collect::().parse::() { syms.push(if sign > 0 { @@ -118,7 +125,7 @@ impl Symbol { Self::SInt((n as i64 * sign) as u64) }); } else { - return Err("invalid integer".to_string()); + return Err(ParseError::BadInt); } continue; @@ -129,17 +136,18 @@ impl Symbol { '"' => { it.next(); - let v = Symbol::take(&mut it, |c| c != '"'); + let v = Symbol::take(&mut it, |c| c != '"').map_err(|_| ParseError::BadStr)?; syms.push(Self::Str(v.iter().collect())); } ' ' | '\t' | '\r' => {} _ => { + let err = ParseError::BadSym(c.to_owned()); + if !c.is_alphanumeric() { - return Err(format!("invalid symbol {}", c)); + return Err(err); } - let v = Symbol::take(&mut it, |c| c.is_alphanumeric()); - + let v = Symbol::take(&mut it, |c| c.is_alphanumeric()).map_err(|_| err)?; syms.push(Self::Id(Some(v.iter().collect()))); continue; } @@ -195,11 +203,13 @@ impl<'a> Parser<'a> { self.next(); loop { - if *self.peek()? == close { - break; - } + let sym = self.peek().map_err(|_| ParseError::ExpectedParens)?; - node.entries.push(self.parse_expr()?); + if *sym == close { + break; + } else { + node.entries.push(self.parse_expr()?); + } } self.expect(close, ParseError::ExpectedParens)?; self.next(); diff --git a/bipc/src/lib.rs b/bipc/src/lib.rs index d483ca7..ad17d40 100644 --- a/bipc/src/lib.rs +++ b/bipc/src/lib.rs @@ -8,7 +8,6 @@ pub type Result = std::result::Result; pub enum Error { ReadError, BadFile, - BadRead(String), BadWrite(std::io::Error), BadPath(std::io::Error), BpError(bp::Error), @@ -20,7 +19,6 @@ impl fmt::Display for Error { match self { Self::ReadError => write!(f, "errors found"), Self::BadFile => write!(f, "invalid text"), - Self::BadRead(e) => write!(f, "{e}"), Self::BadWrite(e) => write!(f, "{e}"), Self::BadPath(e) => write!(f, "{e}"), Self::BpError(e) => write!(f, "{e}"), @@ -35,7 +33,7 @@ fn read_bip(buf: R) -> Result> { .lines() .map(|l| { l.map_or(Err(Error::BadFile), |l| { - bip::Symbol::parse(&l).map_err(Error::BadRead) + bip::Symbol::parse(&l).map_err(Error::ParseError) }) }) .filter_map(|r| r.map_err(|e| errors.push(e)).ok()) @@ -48,7 +46,7 @@ fn read_bip(buf: R) -> Result> { }); if err_count > 0 { - eprintln!("{err_count} errors"); + eprintln!("{err_count} error{}", if err_count == 1 { "" } else { "s" }); Err(Error::ReadError) } else { bip::Parser::new(&syms).parse().map_err(Error::ParseError)