From 071f584e92589e6986caedc936187bebc837eeaf Mon Sep 17 00:00:00 2001 From: Sander Hautvast Date: Fri, 24 Jan 2020 13:50:12 +0100 Subject: [PATCH] scanner now recognizes numeric (f64) literals --- src/scanner.rs | 28 +++++++++++++++++++++- src/tests.rs | 11 +++++++++ src/tokens.rs | 64 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/src/scanner.rs b/src/scanner.rs index 7192830..351018c 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -102,10 +102,36 @@ impl Scanner<'_> { '\t' => {} '\r' => {} '\"' => self.string(), - _ => {} + _ => { + if next_char.is_digit(10) { + self.number(); + } else { + self.report_error(self.line, "unexpected character"); + } + } } } + /// handle number literals + /// advances while characters are considered part of the number + /// finally adds a number token to the list. + fn number(&mut self) { + while self.peek(0).is_digit(10) { + self.advance(); + } + + if self.peek(0) == '.' && self.peek(1).is_digit(10) { + self.advance(); + + while self.peek(0).is_digit(10) { + self.advance(); + } + } + let value: f64 = self.source[self.start..self.current].parse().expect("not a number"); + + self.add_token_literal(NUMBER, Box::new(value)); + } + /// handle string literals /// advances until a terminating double quote is found and then adds the string token to the list /// raises an interpreter error when the double-quote is not found and the end of the source has been reached diff --git a/src/tests.rs b/src/tests.rs index 694401f..8115284 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -46,3 +46,14 @@ fn test_scan_string_literals() { assert_eq!(token.lexeme, "\"hello world\""); assert_eq!(token.get_literal_as_string().unwrap(), "hello world"); } + +#[test] +fn test_scan_numeric_literals() { + let tokens = scan_tokens("0.1").unwrap(); + assert_eq!(tokens.len(), 2); + + let token = tokens.get(0).unwrap(); + assert_eq!(token.token_type, NUMBER); + assert_eq!(token.lexeme, "0.1"); + assert_eq!(token.get_literal_as_float().unwrap(), 0.1); +} diff --git a/src/tokens.rs b/src/tokens.rs index 7765e4b..9f0ba47 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -16,9 +16,13 @@ pub struct Token<'a> { pub token_type: TokenType, } -impl Token<'_>{ - pub fn get_literal_as_string(&self) -> Option<&str>{ - self.literal.downcast_ref::().map(|s|s.as_str()) +impl Token<'_> { + pub fn get_literal_as_string(&self) -> Option<&str> { + self.literal.downcast_ref::().map(|s| s.as_str()) + } + + pub fn get_literal_as_float(&self) -> Option { + self.literal.downcast_ref::().map(|f| *f) } } @@ -40,30 +44,48 @@ impl fmt::Debug for Token<'_> { #[derive(Eq, PartialEq, Debug, Clone, Copy)] pub enum TokenType { // Single-character tokens. - LEFTPAREN, // ( - RIGHTPAREN, // ) - LEFTBRACE, // [ - RIGHTBRACE, // ] - COMMA, // , - DOT, // . - MINUS, // - - PLUS, // + - SEMICOLON, // ; - STAR, // * + LEFTPAREN, + // ( + RIGHTPAREN, + // ) + LEFTBRACE, + // [ + RIGHTBRACE, + // ] + COMMA, + // , + DOT, + // . + MINUS, + // - + PLUS, + // + + SEMICOLON, + // ; + STAR, + // * SLASH, // / // One or two character tokens. - BANG, // ! - BANGEQUAL, // != - EQUAL, // = - EQUALEQUAL, // == - GREATER, // > - GREATEREQUAL, // >= - LESS, // < + BANG, + // ! + BANGEQUAL, + // != + EQUAL, + // = + EQUALEQUAL, + // == + GREATER, + // > + GREATEREQUAL, + // >= + LESS, + // < LESSEQUAL, // <= // Literals. STRING, + NUMBER, - EOF // end of file + EOF, // end of file } \ No newline at end of file