Add division
This commit is contained in:
parent
a048577143
commit
2cf580d111
@ -199,6 +199,11 @@ impl Lexer {
|
|||||||
|
|
||||||
(Token::RightCurlyBrace, (self.position - 1, self.position))
|
(Token::RightCurlyBrace, (self.position - 1, self.position))
|
||||||
}
|
}
|
||||||
|
'/' => {
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
(Token::Slash, (self.position - 1, self.position))
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.position += 1;
|
self.position += 1;
|
||||||
|
|
||||||
@ -425,6 +430,21 @@ impl From<ParseIntError> for LexError {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide() {
|
||||||
|
let input = "42 / 2";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
lex(input),
|
||||||
|
Ok(vec![
|
||||||
|
(Token::Integer(42), (0, 2)),
|
||||||
|
(Token::Slash, (3, 4)),
|
||||||
|
(Token::Integer(2), (5, 6)),
|
||||||
|
(Token::Eof, (6, 6)),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn map() {
|
fn map() {
|
||||||
let input = "{ x = 42, y = 'foobar' }";
|
let input = "{ x = 42, y = 'foobar' }";
|
||||||
|
@ -285,6 +285,23 @@ impl<'src> Parser<'src> {
|
|||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
(Token::Slash, _) => {
|
||||||
|
let operator = Node::new(BinaryOperator::Divide, self.current.1);
|
||||||
|
|
||||||
|
self.next_token()?;
|
||||||
|
|
||||||
|
let right_node = self.parse_node(self.current_precedence())?;
|
||||||
|
let right_end = right_node.position.1;
|
||||||
|
|
||||||
|
return Ok(Node::new(
|
||||||
|
Statement::BinaryOperation {
|
||||||
|
left: Box::new(left_node),
|
||||||
|
operator,
|
||||||
|
right: Box::new(right_node),
|
||||||
|
},
|
||||||
|
(left_start, right_end),
|
||||||
|
));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,6 +525,7 @@ impl<'src> Parser<'src> {
|
|||||||
Token::Greater | Token::GreaterEqual | Token::Less | Token::LessEqual => 5,
|
Token::Greater | Token::GreaterEqual | Token::Less | Token::LessEqual => 5,
|
||||||
Token::Dot => 4,
|
Token::Dot => 4,
|
||||||
Token::Star => 2,
|
Token::Star => 2,
|
||||||
|
Token::Slash => 2,
|
||||||
Token::Plus => 1,
|
Token::Plus => 1,
|
||||||
Token::Minus => 1,
|
Token::Minus => 1,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
@ -577,6 +595,26 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide() {
|
||||||
|
let input = "42 / 2";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse(input),
|
||||||
|
Ok(AbstractSyntaxTree {
|
||||||
|
nodes: [Node::new(
|
||||||
|
Statement::BinaryOperation {
|
||||||
|
left: Box::new(Node::new(Statement::Constant(Value::integer(42)), (0, 2))),
|
||||||
|
operator: Node::new(BinaryOperator::Divide, (3, 4)),
|
||||||
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6)))
|
||||||
|
},
|
||||||
|
(0, 6)
|
||||||
|
)]
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn malformed_assignment() {
|
fn malformed_assignment() {
|
||||||
let input = "false = 1";
|
let input = "false = 1";
|
||||||
|
@ -41,6 +41,7 @@ pub enum Token<'src> {
|
|||||||
RightCurlyBrace,
|
RightCurlyBrace,
|
||||||
RightParenthesis,
|
RightParenthesis,
|
||||||
RightSquareBrace,
|
RightSquareBrace,
|
||||||
|
Slash,
|
||||||
Star,
|
Star,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +75,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::RightParenthesis => TokenOwned::RightParenthesis,
|
Token::RightParenthesis => TokenOwned::RightParenthesis,
|
||||||
Token::RightSquareBrace => TokenOwned::RightSquareBrace,
|
Token::RightSquareBrace => TokenOwned::RightSquareBrace,
|
||||||
Token::Star => TokenOwned::Star,
|
Token::Star => TokenOwned::Star,
|
||||||
|
Token::Slash => TokenOwned::Slash,
|
||||||
Token::String(text) => TokenOwned::String(text.to_string()),
|
Token::String(text) => TokenOwned::String(text.to_string()),
|
||||||
Token::WriteLine => TokenOwned::WriteLine,
|
Token::WriteLine => TokenOwned::WriteLine,
|
||||||
}
|
}
|
||||||
@ -109,6 +111,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::RightSquareBrace => "]",
|
Token::RightSquareBrace => "]",
|
||||||
Token::Star => "*",
|
Token::Star => "*",
|
||||||
Token::String(_) => "string",
|
Token::String(_) => "string",
|
||||||
|
Token::Slash => "/",
|
||||||
Token::WriteLine => "write_line",
|
Token::WriteLine => "write_line",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,6 +154,7 @@ impl<'src> PartialEq for Token<'src> {
|
|||||||
(Token::RightParenthesis, Token::RightParenthesis) => true,
|
(Token::RightParenthesis, Token::RightParenthesis) => true,
|
||||||
(Token::RightSquareBrace, Token::RightSquareBrace) => true,
|
(Token::RightSquareBrace, Token::RightSquareBrace) => true,
|
||||||
(Token::Star, Token::Star) => true,
|
(Token::Star, Token::Star) => true,
|
||||||
|
(Token::Slash, Token::Slash) => true,
|
||||||
(Token::String(left), Token::String(right)) => left == right,
|
(Token::String(left), Token::String(right)) => left == right,
|
||||||
(Token::WriteLine, Token::WriteLine) => true,
|
(Token::WriteLine, Token::WriteLine) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -199,6 +203,7 @@ pub enum TokenOwned {
|
|||||||
RightParenthesis,
|
RightParenthesis,
|
||||||
RightSquareBrace,
|
RightSquareBrace,
|
||||||
Star,
|
Star,
|
||||||
|
Slash,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for TokenOwned {
|
impl Display for TokenOwned {
|
||||||
@ -231,6 +236,7 @@ impl Display for TokenOwned {
|
|||||||
TokenOwned::RightParenthesis => Token::RightParenthesis.fmt(f),
|
TokenOwned::RightParenthesis => Token::RightParenthesis.fmt(f),
|
||||||
TokenOwned::RightSquareBrace => Token::RightSquareBrace.fmt(f),
|
TokenOwned::RightSquareBrace => Token::RightSquareBrace.fmt(f),
|
||||||
TokenOwned::Star => Token::Star.fmt(f),
|
TokenOwned::Star => Token::Star.fmt(f),
|
||||||
|
TokenOwned::Slash => Token::Slash.fmt(f),
|
||||||
TokenOwned::String(string) => write!(f, "{string}"),
|
TokenOwned::String(string) => write!(f, "{string}"),
|
||||||
TokenOwned::WriteLine => Token::WriteLine.fmt(f),
|
TokenOwned::WriteLine => Token::WriteLine.fmt(f),
|
||||||
}
|
}
|
||||||
|
@ -158,6 +158,26 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn divide(&self, other: &Value) -> Result<Value, ValueError> {
|
||||||
|
match (self.inner().as_ref(), other.inner().as_ref()) {
|
||||||
|
(ValueInner::Float(left), ValueInner::Float(right)) => {
|
||||||
|
if right == &0.0 {
|
||||||
|
Err(ValueError::DivisionByZero)
|
||||||
|
} else {
|
||||||
|
Ok(Value::float(left / right))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||||
|
if right == &0 {
|
||||||
|
Err(ValueError::DivisionByZero)
|
||||||
|
} else {
|
||||||
|
Ok(Value::integer(left / right))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ValueError::CannotDivide(self.clone(), other.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn less_than(&self, other: &Value) -> Result<Value, ValueError> {
|
pub fn less_than(&self, other: &Value) -> Result<Value, ValueError> {
|
||||||
match (self.inner().as_ref(), other.inner().as_ref()) {
|
match (self.inner().as_ref(), other.inner().as_ref()) {
|
||||||
(ValueInner::Float(left), ValueInner::Float(right)) => Ok(Value::boolean(left < right)),
|
(ValueInner::Float(left), ValueInner::Float(right)) => Ok(Value::boolean(left < right)),
|
||||||
@ -753,6 +773,7 @@ impl Display for Function {
|
|||||||
pub enum ValueError {
|
pub enum ValueError {
|
||||||
CannotAdd(Value, Value),
|
CannotAdd(Value, Value),
|
||||||
CannotAnd(Value, Value),
|
CannotAnd(Value, Value),
|
||||||
|
CannotDivide(Value, Value),
|
||||||
CannotGreaterThan(Value, Value),
|
CannotGreaterThan(Value, Value),
|
||||||
CannotGreaterThanOrEqual(Value, Value),
|
CannotGreaterThanOrEqual(Value, Value),
|
||||||
CannotLessThan(Value, Value),
|
CannotLessThan(Value, Value),
|
||||||
@ -760,6 +781,7 @@ pub enum ValueError {
|
|||||||
CannotMultiply(Value, Value),
|
CannotMultiply(Value, Value),
|
||||||
CannotSubtract(Value, Value),
|
CannotSubtract(Value, Value),
|
||||||
CannotOr(Value, Value),
|
CannotOr(Value, Value),
|
||||||
|
DivisionByZero,
|
||||||
ExpectedList(Value),
|
ExpectedList(Value),
|
||||||
IndexOutOfBounds { value: Value, index: i64 },
|
IndexOutOfBounds { value: Value, index: i64 },
|
||||||
}
|
}
|
||||||
@ -775,6 +797,9 @@ impl Display for ValueError {
|
|||||||
"Cannot use logical and operation on {} and {}",
|
"Cannot use logical and operation on {} and {}",
|
||||||
left, right
|
left, right
|
||||||
),
|
),
|
||||||
|
ValueError::CannotDivide(left, right) => {
|
||||||
|
write!(f, "Cannot divide {} by {}", left, right)
|
||||||
|
}
|
||||||
ValueError::CannotMultiply(left, right) => {
|
ValueError::CannotMultiply(left, right) => {
|
||||||
write!(f, "Cannot multiply {} and {}", left, right)
|
write!(f, "Cannot multiply {} and {}", left, right)
|
||||||
}
|
}
|
||||||
@ -794,6 +819,7 @@ impl Display for ValueError {
|
|||||||
left, right
|
left, right
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
ValueError::DivisionByZero => write!(f, "Division by zero"),
|
||||||
ValueError::IndexOutOfBounds { value, index } => {
|
ValueError::IndexOutOfBounds { value, index } => {
|
||||||
write!(f, "{} does not have an index of {}", value, index)
|
write!(f, "{} does not have an index of {}", value, index)
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ impl Vm {
|
|||||||
let result = match operator.inner {
|
let result = match operator.inner {
|
||||||
BinaryOperator::Add => left_value.add(&right_value),
|
BinaryOperator::Add => left_value.add(&right_value),
|
||||||
BinaryOperator::And => left_value.and(&right_value),
|
BinaryOperator::And => left_value.and(&right_value),
|
||||||
BinaryOperator::Divide => todo!(),
|
BinaryOperator::Divide => left_value.divide(&right_value),
|
||||||
BinaryOperator::Greater => left_value.greater_than(&right_value),
|
BinaryOperator::Greater => left_value.greater_than(&right_value),
|
||||||
BinaryOperator::GreaterOrEqual => {
|
BinaryOperator::GreaterOrEqual => {
|
||||||
left_value.greater_than_or_equal(&right_value)
|
left_value.greater_than_or_equal(&right_value)
|
||||||
@ -432,6 +432,16 @@ impl Display for VmError {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide() {
|
||||||
|
let input = "42 / 2";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
run(input, &mut HashMap::new()),
|
||||||
|
Ok(Some(Value::integer(21)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn less_than() {
|
fn less_than() {
|
||||||
let input = "2 < 3";
|
let input = "2 < 3";
|
||||||
|
Loading…
Reference in New Issue
Block a user