Attempting numbers; tests are failing though :-(
This commit is contained in:
parent
9e3d4f155e
commit
aba541ed4d
3 changed files with 93 additions and 11 deletions
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue