From 5e500e9ec3f36cd2daca318bbdaf32dac078fbc7 Mon Sep 17 00:00:00 2001 From: Lewis Dale Date: Fri, 27 Jan 2023 13:51:41 +0000 Subject: [PATCH] Start working on expressions --- src/basic.rs | 11 ++-- src/node.rs | 2 +- src/parsers.rs | 1 + src/parsers/expressions.rs | 119 +++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 src/parsers/expressions.rs diff --git a/src/basic.rs b/src/basic.rs index be82a67..191425b 100644 --- a/src/basic.rs +++ b/src/basic.rs @@ -1,9 +1,12 @@ -use std::{collections::HashMap}; +use std::collections::HashMap; use nom::{bytes::complete::tag, multi::separated_list0, IResult}; -use crate::{parsers, commands::{Primitive, PrintOutput, Command}, node::Node}; - +use crate::{ + commands::{Command, Primitive, PrintOutput}, + node::Node, + parsers, +}; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Program { @@ -95,8 +98,8 @@ mod tests { use super::{Command, Node, Primitive, Program}; use crate::{ + commands::Line, parsers::{commands::parse_line, generic::read_string}, - commands::Line }; #[test] diff --git a/src/node.rs b/src/node.rs index 0dd3cf4..bed2431 100644 --- a/src/node.rs +++ b/src/node.rs @@ -34,4 +34,4 @@ impl Node { None } } -} \ No newline at end of file +} diff --git a/src/parsers.rs b/src/parsers.rs index 0ab2bfb..663273f 100644 --- a/src/parsers.rs +++ b/src/parsers.rs @@ -1,3 +1,4 @@ pub mod commands; +pub mod expressions; pub mod generic; pub mod variables; diff --git a/src/parsers/expressions.rs b/src/parsers/expressions.rs new file mode 100644 index 0000000..73c6ba0 --- /dev/null +++ b/src/parsers/expressions.rs @@ -0,0 +1,119 @@ +use nom::{ + character::{complete::i64 as cci64, streaming::one_of}, + combinator::{map, value}, + sequence::tuple, + IResult, branch::alt, multi::many0, +}; + +use crate::commands::Primitive; + +use super::variables::parse_int; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Operator { + Add, + Subtract, + Divide, + Multiply, +} + +impl From for Operator { + fn from(value: char) -> Self { + match value { + '+' => Operator::Add, + '-' => Operator::Subtract, + '/' => Operator::Divide, + '*' => Operator::Multiply, + _ => panic!("Unrecognised character"), + } + } +} + +pub type Expression = (ExpressionTarget, Operator, ExpressionTarget); + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum ExpressionTarget { + Val(Primitive), + Expression(Box), +} + +impl From for ExpressionTarget { + fn from(value: i64) -> Self { + ExpressionTarget::Val(Primitive::Int(value)) + } +} + +impl From for ExpressionTarget { + fn from(value: Expression) -> Self { + Self::Expression(Box::new(value)) + } +} + +fn parse_expression_target(i: &str) -> IResult<&str, ExpressionTarget> { + alt(( + map(parse_expression, ExpressionTarget::from), + map(cci64, ExpressionTarget::from) + ))(i) +} + +pub fn parse_expression(i: &str) -> IResult<&str, Expression> { + tuple((map(cci64, ExpressionTarget::from), + map(one_of("*/+-"), Operator::from), + map(cci64, ExpressionTarget::from)))(i) +} + +pub fn parse_full_expression(i: &str) -> IResult<&str, Expression> { + tuple(( + parse_expression_target, + map(one_of("*/+-"), Operator::from), + parse_expression_target, + ))(i) +} + +#[cfg(test)] +mod tests { + use crate::commands::Primitive; + + use super::{parse_full_expression, Expression, ExpressionTarget, Operator}; + + #[test] + fn it_parses_a_simple_expression() { + let input = "1+1"; + let expected: Expression = ( + ExpressionTarget::Val(Primitive::Int(1)), + Operator::Add, + ExpressionTarget::Val(Primitive::Int(1)), + ); + let (_, result) = parse_full_expression(input).unwrap(); + assert_eq!(expected, result); + } + + #[test] + fn it_parses_a_subtraction_expression() { + let input = "1-1"; + let expected: Expression = ( + ExpressionTarget::Val(Primitive::Int(1)), + Operator::Subtract, + ExpressionTarget::Val(Primitive::Int(1)), + ); + let (_, result) = parse_full_expression(input).unwrap(); + assert_eq!(expected, result); + } + + #[test] + fn it_parses_a_left_hand_subexpression() { + let input = "1+1+2"; + let expected: Expression = ( + ExpressionTarget::Expression(Box::new(( + ExpressionTarget::Val(Primitive::Int(1)), + Operator::Add, + ExpressionTarget::Val(Primitive::Int(1)) + ))), + Operator::Add, + ExpressionTarget::Val(Primitive::Int(2)) + ); + + let (_, result) = parse_full_expression(input).unwrap(); + assert_eq!(expected, result); + } +}