diff --git a/dust-lang/src/lex.rs b/dust-lang/src/lex.rs index f1a0271..2e8d75e 100644 --- a/dust-lang/src/lex.rs +++ b/dust-lang/src/lex.rs @@ -121,7 +121,7 @@ impl<'a> Lexer<'a> { } else { let integer = self.input[start_pos..self.position].parse::()?; - Ok((Token::Number(integer), (start_pos, self.position))) + Ok((Token::Integer(integer), (start_pos, self.position))) } } @@ -166,7 +166,7 @@ mod tests { use super::*; #[test] - fn float() { + fn small_float() { let input = "1.23"; assert_eq!( @@ -175,6 +175,20 @@ mod tests { ) } + #[test] + #[allow(clippy::excessive_precision)] + fn big_float() { + let input = "123456789.123456789"; + + assert_eq!( + lex(input), + Ok(vec![ + (Token::Float(123456789.123456789), (0, 19)), + (Token::Eof, (19, 19)), + ]) + ) + } + #[test] fn add() { let input = "1 + 2"; @@ -182,9 +196,9 @@ mod tests { assert_eq!( lex(input), Ok(vec![ - (Token::Number(1), (0, 1)), + (Token::Integer(1), (0, 1)), (Token::Plus, (2, 3)), - (Token::Number(2), (4, 5)), + (Token::Integer(2), (4, 5)), (Token::Eof, (5, 5)), ]) ) @@ -197,9 +211,9 @@ mod tests { assert_eq!( lex(input), Ok(vec![ - (Token::Number(1), (0, 1)), + (Token::Integer(1), (0, 1)), (Token::Star, (2, 3)), - (Token::Number(2), (4, 5)), + (Token::Integer(2), (4, 5)), (Token::Eof, (5, 5)), ]) ) @@ -212,11 +226,11 @@ mod tests { assert_eq!( lex(input), Ok(vec![ - (Token::Number(1), (0, 1)), + (Token::Integer(1), (0, 1)), (Token::Plus, (2, 3)), - (Token::Number(2), (4, 5)), + (Token::Integer(2), (4, 5)), (Token::Star, (6, 7)), - (Token::Number(3), (8, 9)), + (Token::Integer(3), (8, 9)), (Token::Eof, (9, 9)), ]) ); @@ -231,11 +245,11 @@ mod tests { Ok(vec![ (Token::Identifier(Identifier::new("a")), (0, 1)), (Token::Equal, (2, 3)), - (Token::Number(1), (4, 5)), + (Token::Integer(1), (4, 5)), (Token::Plus, (6, 7)), - (Token::Number(2), (8, 9)), + (Token::Integer(2), (8, 9)), (Token::Star, (10, 11)), - (Token::Number(3), (12, 13)), + (Token::Integer(3), (12, 13)), (Token::Eof, (13, 13)), ]) ); diff --git a/dust-lang/src/parse.rs b/dust-lang/src/parse.rs index 360b2ed..5789288 100644 --- a/dust-lang/src/parse.rs +++ b/dust-lang/src/parse.rs @@ -4,7 +4,7 @@ use crate::{ Span, Token, Value, }; -pub fn parse(input: &str) -> Result<(Instruction, Span), ParseError> { +pub fn parse(input: &str) -> Result { let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); @@ -12,7 +12,19 @@ pub fn parse(input: &str) -> Result<(Instruction, Span), ParseError> { } #[derive(Debug, PartialEq, Clone)] -pub enum Instruction { +pub struct Instruction { + pub operation: Operation, + pub span: Span, +} + +impl Instruction { + pub fn new(operation: Operation, span: Span) -> Self { + Self { operation, span } + } +} + +#[derive(Debug, PartialEq, Clone)] +pub enum Operation { Add(Box<(Instruction, Instruction)>), Assign(Box<(Instruction, Instruction)>), Constant(Value), @@ -28,18 +40,12 @@ pub struct Parser<'src> { impl<'src> Parser<'src> { pub fn new(lexer: Lexer<'src>) -> Self { let mut lexer = lexer; - let current_token = lexer - .next_token() - .map(|(token, _)| token) - .unwrap_or(Token::Eof); + let current = lexer.next_token().unwrap_or((Token::Eof, (0, 0))); - Parser { - lexer, - current: (current_token, (0, 0)), - } + Parser { lexer, current } } - pub fn parse(&mut self) -> Result<(Instruction, Span), ParseError> { + pub fn parse(&mut self) -> Result { self.parse_instruction(0) } @@ -49,70 +55,87 @@ impl<'src> Parser<'src> { Ok(()) } - fn parse_instruction(&mut self, precedence: u8) -> Result<(Instruction, Span), ParseError> { - let (left_instruction, left_span) = self.parse_primary()?; + fn parse_instruction(&mut self, precedence: u8) -> Result { + let left_instruction = self.parse_primary()?; + let left_start = left_instruction.span.0; if precedence < self.current_precedence() { match &self.current { (Token::Plus, _) => { self.next_token()?; - let (right_instruction, right_span) = - self.parse_instruction(self.current_precedence())?; + let right_instruction = self.parse_instruction(self.current_precedence())?; + let right_end = right_instruction.span.1; - return Ok(( - Instruction::Add(Box::new((left_instruction, right_instruction))), - (left_span.0, right_span.1), + return Ok(Instruction::new( + Operation::Add(Box::new((left_instruction, right_instruction))), + (left_start, right_end), )); } (Token::Star, _) => { self.next_token()?; - let (right_instruction, right_span) = - self.parse_instruction(self.current_precedence())?; + let right_instruction = self.parse_instruction(self.current_precedence())?; + let right_end = right_instruction.span.1; - return Ok(( - Instruction::Multiply(Box::new((left_instruction, right_instruction))), - (left_span.0, right_span.1), + return Ok(Instruction::new( + Operation::Multiply(Box::new((left_instruction, right_instruction))), + (left_start, right_end), )); } (Token::Equal, _) => { self.next_token()?; - let (right_instruction, right_span) = - self.parse_instruction(self.current_precedence())?; + let right_instruction = self.parse_instruction(self.current_precedence())?; + let right_end = right_instruction.span.1; - return Ok(( - Instruction::Assign(Box::new((left_instruction, right_instruction))), - (left_span.0, right_span.1), + return Ok(Instruction::new( + Operation::Assign(Box::new((left_instruction, right_instruction))), + (left_start, right_end), )); } _ => {} } } - Ok((left_instruction, left_span)) + Ok(left_instruction) } - fn parse_primary(&mut self) -> Result<(Instruction, Span), ParseError> { + fn parse_primary(&mut self) -> Result { match self.current.clone() { - (Token::Number(int), span) => { + (Token::Float(float), span) => { self.next_token()?; - Ok((Instruction::Constant(Value::integer(int)), span)) + + Ok(Instruction::new( + Operation::Constant(Value::float(float)), + span, + )) + } + (Token::Integer(int), span) => { + self.next_token()?; + + Ok(Instruction::new( + Operation::Constant(Value::integer(int)), + span, + )) } (Token::Identifier(identifier), span) => { self.next_token()?; - Ok((Instruction::Identifier(identifier), span)) + + Ok(Instruction::new(Operation::Identifier(identifier), span)) } (Token::LeftParenthesis, left_span) => { self.next_token()?; - let (instruction, _) = self.parse_instruction(0)?; + let instruction = self.parse_instruction(0)?; if let (Token::RightParenthesis, right_span) = self.current { self.next_token()?; - Ok((instruction, (left_span.0, right_span.1))) + Ok(Instruction::new( + instruction.operation, + (left_span.0, right_span.1), + )) } else { Err(ParseError::ExpectedClosingParenthesis) } @@ -149,16 +172,29 @@ mod tests { use super::*; + #[test] + fn float() { + let input = "42.0"; + + assert_eq!( + parse(input), + Ok(Instruction::new( + Operation::Constant(Value::float(42.0)), + (0, 4) + )) + ); + } + #[test] fn add() { let input = "1 + 2"; assert_eq!( parse(input), - Ok(( - Instruction::Add(Box::new(( - Instruction::Constant(Value::integer(1)), - Instruction::Constant(Value::integer(2)) + Ok(Instruction::new( + Operation::Add(Box::new(( + Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), + Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), ))), (0, 5) )) @@ -171,10 +207,10 @@ mod tests { assert_eq!( parse(input), - Ok(( - Instruction::Multiply(Box::new(( - Instruction::Constant(Value::integer(1)), - Instruction::Constant(Value::integer(2)) + Ok(Instruction::new( + Operation::Multiply(Box::new(( + Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), + Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), ))), (0, 5) )) @@ -187,13 +223,16 @@ mod tests { assert_eq!( parse(input), - Ok(( - Instruction::Add(Box::new(( - Instruction::Constant(Value::integer(1)), - Instruction::Multiply(Box::new(( - Instruction::Constant(Value::integer(2)), - Instruction::Constant(Value::integer(3)) - ))) + Ok(Instruction::new( + Operation::Add(Box::new(( + Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), + Instruction::new( + Operation::Multiply(Box::new(( + Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), + Instruction::new(Operation::Constant(Value::integer(3)), (8, 9)), + ))), + (4, 9) + ), ))), (0, 9) )) @@ -206,16 +245,28 @@ mod tests { assert_eq!( parse(input), - Ok(( - Instruction::Assign(Box::new(( - Instruction::Identifier(Identifier::new("a")), - Instruction::Add(Box::new(( - Instruction::Constant(Value::integer(1)), - Instruction::Multiply(Box::new(( - Instruction::Constant(Value::integer(2)), - Instruction::Constant(Value::integer(3)) - ))) - ))) + Ok(Instruction::new( + Operation::Assign(Box::new(( + Instruction::new(Operation::Identifier(Identifier::new("a")), (0, 1)), + Instruction::new( + Operation::Add(Box::new(( + Instruction::new(Operation::Constant(Value::integer(1)), (4, 5)), + Instruction::new( + Operation::Multiply(Box::new(( + Instruction::new( + Operation::Constant(Value::integer(2)), + (8, 9) + ), + Instruction::new( + Operation::Constant(Value::integer(3)), + (12, 13) + ), + ))), + (8, 13) + ), + ))), + (4, 13) + ), ))), (0, 13) )) diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index ad1a31b..51d3812 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -5,7 +5,7 @@ pub enum Token { Eof, Equal, Identifier(Identifier), - Number(i64), + Integer(i64), Plus, Star, LeftParenthesis,