Attempting numbers; tests are failing though :-(

This commit is contained in:
Eryn Wells 2016-12-26 18:23:58 -07:00
parent 9e3d4f155e
commit aba541ed4d
3 changed files with 93 additions and 11 deletions

View file

@ -5,9 +5,11 @@
pub mod token; pub mod token;
mod char; mod char;
mod charset; mod charset;
mod number;
mod str; mod str;
use self::char::Lexable; use self::char::Lexable;
use self::number::NumberBuilder;
use self::str::CharAt; use self::str::CharAt;
use self::str::RelativeIndexable; use self::str::RelativeIndexable;
use self::token::Lex; use self::token::Lex;
@ -15,11 +17,13 @@ use self::token::Token;
#[derive(Debug)] #[derive(Debug)]
enum State { enum State {
Comment,
Initial, Initial,
Identifier, Identifier,
Dot, Dot,
Hash, Hash,
Comment, Number,
NumberDecimal,
String, String,
} }
@ -29,6 +33,7 @@ pub struct Lexer {
forward: usize, forward: usize,
line: u32, line: u32,
state: State, state: State,
number_builder: NumberBuilder,
} }
impl Lexer { impl Lexer {
@ -39,6 +44,7 @@ impl Lexer {
forward: 0, forward: 0,
line: 1, line: 1,
state: State::Initial, state: State::Initial,
number_builder: NumberBuilder::new(),
} }
} }
} }
@ -111,6 +117,13 @@ impl Lexer {
self.advance(); self.advance();
} }
else if c.is_digit(10) {
self.number_builder = NumberBuilder::new();
self.number_builder.extend_value(c);
self.state = State::Number;
self.advance();
}
else if c.is_whitespace() { else if c.is_whitespace() {
if c.is_newline() { if c.is_newline() {
self.handle_newline(); self.handle_newline();
@ -148,6 +161,12 @@ impl Lexer {
*token = Some(Token::Dot); *token = Some(Token::Dot);
self.retract(); self.retract();
} }
else if c.is_digit(10) {
self.number_builder = NumberBuilder::new();
self.number_builder.extend_decimal_value(c);
self.state = State::NumberDecimal;
self.advance();
}
else { else {
assert!(false, "Invalid token character: '{}'", c); assert!(false, "Invalid token character: '{}'", c);
} }
@ -167,6 +186,39 @@ impl Lexer {
} }
} }
fn state_number(&mut self, c: char, token: &mut Option<Token>) {
if c.is_digit(self.number_builder.radix_value()) {
self.number_builder.extend_value(c);
self.advance();
}
else if c.is_dot() {
self.number_builder.extend_decimal_value(c);
self.state = State::NumberDecimal;
self.advance();
}
else if c.is_identifier_delimiter() {
*token = Some(Token::Number(self.number_builder.resolve()));
self.retract();
}
else {
assert!(false, "Invalid token character: '{}'", c);
}
}
fn state_number_decimal(&mut self, c: char, token: &mut Option<Token>) {
if c.is_digit(self.number_builder.radix_value()) {
self.number_builder.extend_decimal_value(c);
self.advance();
}
else if c.is_identifier_delimiter() {
*token = Some(Token::Number(self.number_builder.resolve()));
self.retract();
}
else {
assert!(false, "Invalid token character: '{}'", c);
}
}
fn state_string(&mut self, c: char, token: &mut Option<Token>) { fn state_string(&mut self, c: char, token: &mut Option<Token>) {
self.advance(); self.advance();
if c.is_string_quote() { if c.is_string_quote() {
@ -209,6 +261,8 @@ impl Iterator for Lexer {
State::Identifier => self.state_identifier(c, &mut token), State::Identifier => self.state_identifier(c, &mut token),
State::Dot => self.state_dot(c, &mut token), State::Dot => self.state_dot(c, &mut token),
State::Hash => self.state_hash(c, &mut token), State::Hash => self.state_hash(c, &mut token),
State::Number => self.state_number(c, &mut token),
State::NumberDecimal => self.state_number_decimal(c, &mut token),
State::String => self.state_string(c, &mut token), State::String => self.state_string(c, &mut token),
State::Comment => self.state_comment(c, &mut token), State::Comment => self.state_comment(c, &mut token),
} }
@ -230,6 +284,7 @@ impl Iterator for Lexer {
mod tests { mod tests {
use std::iter::Iterator; use std::iter::Iterator;
use super::*; use super::*;
use super::number::*;
use super::token::*; use super::token::*;
#[test] #[test]
@ -274,6 +329,13 @@ mod tests {
check_single_token("\"abc\"", Token::String(String::from("\"abc\""))); check_single_token("\"abc\"", Token::String(String::from("\"abc\"")));
} }
#[test]
fn lexer_finds_numbers() {
check_single_token("34", Token::Number(Number::new(34.0)));
check_single_token(".34", Token::Number(Number::new(0.34)));
check_single_token("0.34", Token::Number(Number::new(0.34)));
}
fn check_single_token(input: &str, expected: Token) { fn check_single_token(input: &str, expected: Token) {
let mut lexer = Lexer::new(input); let mut lexer = Lexer::new(input);
assert_next_token(&mut lexer, &expected); assert_next_token(&mut lexer, &expected);

View file

@ -2,8 +2,13 @@
* Eryn Wells <eryn@erynwells.me> * Eryn Wells <eryn@erynwells.me>
*/ */
struct Number { #[derive(PartialEq, Debug)]
value: f64, pub struct Number { value: f64, }
impl Number {
pub fn new(value: f64) -> Number {
Number { value: value }
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -14,6 +19,7 @@ pub struct NumberBuilder {
exact: bool, exact: bool,
radix: Radix, radix: Radix,
value: f64, value: f64,
point: u16,
} }
impl NumberBuilder { impl NumberBuilder {
@ -22,6 +28,7 @@ impl NumberBuilder {
exact: false, exact: false,
radix: Radix::Dec, radix: Radix::Dec,
value: 0.0, value: 0.0,
point: 0,
} }
} }
@ -37,7 +44,12 @@ impl NumberBuilder {
pub fn resolve(&self) -> Number { pub fn resolve(&self) -> Number {
// TODO: Convert fields to Number type. // TODO: Convert fields to Number type.
Number { value: 0.0 } let value = if self.point == 0 {
self.value
} else {
self.value / (self.point * 10) as f64
};
Number { value: value }
} }
pub fn extend_value<'a>(&'a mut self, digit: char) -> &'a mut Self { pub fn extend_value<'a>(&'a mut self, digit: char) -> &'a mut Self {
@ -50,6 +62,12 @@ impl NumberBuilder {
self self
} }
pub fn extend_decimal_value<'a>(&'a mut self, digit: char) -> &'a mut Self {
self.extend_value(digit);
self.point += 1;
self
}
pub fn radix_value(&self) -> u32 { pub fn radix_value(&self) -> u32 {
self.radix.value() as u32 self.radix.value() as u32
} }

View file

@ -2,17 +2,19 @@
* Eryn Wells <eryn@erynwells.me> * Eryn Wells <eryn@erynwells.me>
*/ */
#[derive(Debug)] use lexer::number::Number;
#[derive(PartialEq)]
#[derive(PartialEq, Debug)]
pub enum Token { pub enum Token {
LeftParen(String), Boolean(bool),
LeftVectorParen, Comment(String),
RightParen(String),
Dot, Dot,
Identifier(String), Identifier(String),
Boolean(bool), LeftParen(String),
LeftVectorParen,
Number(Number),
RightParen(String),
String(String), String(String),
Comment(String),
} }
/// A Lex is a Token extracted from a specific position in an input. It contains useful information about the token's /// A Lex is a Token extracted from a specific position in an input. It contains useful information about the token's