From 4d760237752dd099155b19ca04967edfa34a4103 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 7 Mar 2024 05:37:26 -0500 Subject: [PATCH] Add Operator token type --- src/lexer.rs | 81 +++++++++++++++++++++++++++++++++++++------- src/parser.rs | 40 ++++++++++++++-------- tests/expressions.rs | 6 ++++ 3 files changed, 99 insertions(+), 28 deletions(-) diff --git a/src/lexer.rs b/src/lexer.rs index a7662c1..327ea0c 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -11,11 +11,56 @@ pub enum Token<'src> { Float(f64), String(&'src str), Identifier(&'src str), - Operator(&'src str), + Operator(Operator), Control(&'src str), Keyword(&'src str), } +#[derive(Clone, Debug, PartialEq)] +pub enum Operator { + Add, + AddAssign, + And, + Assign, + Divide, + Equal, + Greater, + GreaterOrEqual, + Less, + LessOrEqual, + Modulo, + Multiply, + Not, + NotEqual, + Or, + SubAssign, + Subtract, +} + +impl Display for Operator { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Operator::Add => write!(f, "+"), + Operator::AddAssign => write!(f, "+="), + Operator::And => write!(f, "&&"), + Operator::Assign => write!(f, "="), + Operator::Divide => write!(f, "="), + Operator::Equal => write!(f, "=="), + Operator::Greater => write!(f, ">"), + Operator::GreaterOrEqual => write!(f, ">="), + Operator::Less => write!(f, "<"), + Operator::LessOrEqual => write!(f, "<="), + Operator::Modulo => write!(f, "%"), + Operator::Multiply => write!(f, "*"), + Operator::Not => write!(f, "!"), + Operator::NotEqual => write!(f, "!="), + Operator::Or => write!(f, "||"), + Operator::SubAssign => write!(f, "-="), + Operator::Subtract => write!(f, "-"), + } + } +} + impl<'src> Display for Token<'src> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { @@ -24,7 +69,7 @@ impl<'src> Display for Token<'src> { Token::Float(float) => write!(f, "{float}"), Token::String(string) => write!(f, "{string}"), Token::Identifier(string) => write!(f, "{string}"), - Token::Operator(string) => write!(f, "{string}"), + Token::Operator(operator) => write!(f, "{operator}"), Token::Control(string) => write!(f, "{string}"), Token::Keyword(string) => write!(f, "{string}"), } @@ -88,17 +133,27 @@ pub fn lexer<'src>() -> impl Parser< let identifier = text::ident().map(|text: &str| Token::Identifier(text)); let operator = choice(( - just("==").padded(), - just("!=").padded(), - just(">").padded(), - just("<").padded(), - just(">=").padded(), - just("<=").padded(), - just("&&").padded(), - just("||").padded(), - just("=").padded(), - just("+=").padded(), - just("-=").padded(), + // logic + just("&&").padded().to(Operator::And), + just("==").padded().to(Operator::Equal), + just("!=").padded().to(Operator::NotEqual), + just(">").padded().to(Operator::Greater), + just(">=").padded().to(Operator::GreaterOrEqual), + just("<").padded().to(Operator::Less), + just("<=").padded().to(Operator::LessOrEqual), + just("!").padded().to(Operator::Not), + just("!=").padded().to(Operator::NotEqual), + just("||").padded().to(Operator::Or), + // math + just("+").padded().to(Operator::Add), + just("-").padded().to(Operator::Subtract), + just("*").padded().to(Operator::Multiply), + just("/").padded().to(Operator::Divide), + just("%").padded().to(Operator::Modulo), + // assignment + just("=").padded().to(Operator::Assign), + just("+=").padded().to(Operator::AddAssign), + just("-=").padded().to(Operator::SubAssign), )) .map(Token::Operator); diff --git a/src/parser.rs b/src/parser.rs index f97749a..e5c0d1c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,7 +2,11 @@ use std::{cell::RefCell, collections::HashMap}; use chumsky::{input::SpannedInput, pratt::*, prelude::*}; -use crate::{abstract_tree::*, error::Error, lexer::Token}; +use crate::{ + abstract_tree::*, + error::Error, + lexer::{Operator, Token}, +}; pub type DustParser<'src> = Boxed< 'src, @@ -84,33 +88,39 @@ pub fn parser<'src>() -> DustParser<'src> { .delimited_by(just(Token::Control("(")), just(Token::Control(")"))), )); + use Operator::*; + let logic = atom .pratt(( - prefix(2, just(Token::Operator("!")), |expression| { + prefix(2, just(Token::Operator(Not)), |expression| { Expression::Logic(Box::new(Logic::Not(expression))) }), - infix(left(1), just(Token::Operator("==")), |left, right| { + infix(left(1), just(Token::Operator(Equal)), |left, right| { Expression::Logic(Box::new(Logic::Equal(left, right))) }), - infix(left(1), just(Token::Operator("!=")), |left, right| { + infix(left(1), just(Token::Operator(NotEqual)), |left, right| { Expression::Logic(Box::new(Logic::NotEqual(left, right))) }), - infix(left(1), just(Token::Operator(">")), |left, right| { + infix(left(1), just(Token::Operator(Greater)), |left, right| { Expression::Logic(Box::new(Logic::Greater(left, right))) }), - infix(left(1), just(Token::Operator("<")), |left, right| { + infix(left(1), just(Token::Operator(Less)), |left, right| { Expression::Logic(Box::new(Logic::Less(left, right))) }), - infix(left(1), just(Token::Operator(">=")), |left, right| { - Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right))) - }), - infix(left(1), just(Token::Operator("<=")), |left, right| { - Expression::Logic(Box::new(Logic::LessOrEqual(left, right))) - }), - infix(left(1), just(Token::Operator("&&")), |left, right| { + infix( + left(1), + just(Token::Operator(GreaterOrEqual)), + |left, right| Expression::Logic(Box::new(Logic::GreaterOrEqual(left, right))), + ), + infix( + left(1), + just(Token::Operator(LessOrEqual)), + |left, right| Expression::Logic(Box::new(Logic::LessOrEqual(left, right))), + ), + infix(left(1), just(Token::Operator(And)), |left, right| { Expression::Logic(Box::new(Logic::And(left, right))) }), - infix(left(1), just(Token::Operator("||")), |left, right| { + infix(left(1), just(Token::Operator(Or)), |left, right| { Expression::Logic(Box::new(Logic::Or(left, right))) }), )) @@ -155,7 +165,7 @@ pub fn parser<'src>() -> DustParser<'src> { let assignment = identifier .then(type_specification.clone().or_not()) - .then_ignore(just(Token::Operator("="))) + .then_ignore(just(Token::Operator(Operator::Assign))) .then(statement.clone()) .map(|((identifier, r#type), statement)| { Statement::Assignment(Assignment::new(identifier, r#type, statement)) diff --git a/tests/expressions.rs b/tests/expressions.rs index 7c63d11..b26dad5 100644 --- a/tests/expressions.rs +++ b/tests/expressions.rs @@ -8,3 +8,9 @@ fn logic() { Ok(Value::boolean(true)) ); } + +#[test] +fn math() { + assert_eq!(interpret("1 + 1"), Ok(Value::integer(2))); + assert_eq!(interpret("21 + 19 + 1 * 2"), Ok(Value::integer(42))); +}