From f0bcd451ef040cd7de9b51593089a3b5954447fb Mon Sep 17 00:00:00 2001 From: c-kirkeby Date: Thu, 21 Sep 2023 21:28:01 +1000 Subject: [PATCH] feat: add number() --- src/scanner.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/token.rs | 1 + 2 files changed, 60 insertions(+) diff --git a/src/scanner.rs b/src/scanner.rs index 4104060..a0a672d 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -94,6 +94,7 @@ impl Scanner { b' ' | b'\r' | b'\t' => (), b'\n' => self.line += 1, b'"' => self.string()?, + b'0'..=b'9' => self.number()?, _ => bail!("Unexpected character on line {}", self.line), } Ok(()) @@ -134,6 +135,13 @@ impl Scanner { return self.source[self.current]; } + fn peek_next(&self) -> u8 { + if self.current + 1 >= self.source.len() { + return b'\0'; + } + return self.source[self.current + 1]; + } + fn string(&mut self) -> Result<()> { while self.peek() != b'"' && !self.is_at_end() { if self.peek() == b'\n' { @@ -152,6 +160,32 @@ impl Scanner { self.add_token(TokenType::String, Some(Literal::String(value.to_vec()))); Ok(()) } + + fn is_digit(c: u8) -> bool { + c >= b'0' && c <= b'9' + } + + fn number(&mut self) -> Result<()> { + while Self::is_digit(self.peek()) { + self.advance(); + } + + if self.peek() == b'.' && Self::is_digit(self.peek_next()) { + self.advance(); + + while Self::is_digit(self.peek()) { + self.advance(); + } + } + + self.add_token( + TokenType::Number, + Some(Literal::Number( + String::from_utf8_lossy(&self.source[self.start..self.current]).parse::()?, + )), + ); + Ok(()) + } } #[cfg(test)] @@ -182,4 +216,29 @@ mod tests { ); Ok(()) } + + #[test] + fn test_scan_tokens_number() -> Result<()> { + let mut scanner = Scanner::new("123.45\n321".to_string()); + scanner.scan_tokens()?; + assert_eq!( + scanner.tokens, + vec![ + Token::new( + TokenType::Number, + String::from("123.45"), + Some(Literal::Number(123.45)), + 1 + ), + Token::new( + TokenType::Number, + String::from("321"), + Some(Literal::Number(321.0)), + 2 + ), + Token::new(TokenType::EOF, String::from(""), None, 2) + ] + ); + Ok(()) + } } diff --git a/src/token.rs b/src/token.rs index 224d1bc..2104b10 100644 --- a/src/token.rs +++ b/src/token.rs @@ -5,6 +5,7 @@ use std::fmt; #[allow(dead_code)] pub enum Literal { String(Vec), + Number(f64), None, }