diff --git a/src/calc/interpreter.rs b/src/calc/interpreter.rs index 3729f3b..27e6e33 100644 --- a/src/calc/interpreter.rs +++ b/src/calc/interpreter.rs @@ -1,9 +1,9 @@ use std::{collections::HashMap, fmt::Display}; -use crate::{CellValue, Sheet}; +use crate::{calc::parser::BinOp, CellValue, Sheet}; use super::{ - parser::{Call, Expr, Literal}, + parser::{Call, Closure, Expr, Literal}, Token, }; @@ -13,6 +13,19 @@ pub enum Interpret { Text(String), Values(Vec), Bool(bool), + Closure(Closure), +} + +impl Interpret { + fn get_type(&self) -> &'static str { + match self { + Interpret::Number(_) => "Number", + Interpret::Text(_) => "Text", + Interpret::Values(_) => "Range", + Interpret::Bool(_) => "Bool", + Interpret::Closure(_) => "Closure", + } + } } #[derive(PartialEq, Debug, Clone)] @@ -24,6 +37,9 @@ pub enum InterpretError { FunctionNotExist, InvalidFunction, InvalidArgument, + ClosureBinOp, + ClosureInvalidArg, + ExpectedArg(String), } impl Display for InterpretError { @@ -36,14 +52,21 @@ impl Display for InterpretError { InterpretError::FunctionNotExist => "Function does not exist", InterpretError::InvalidFunction => "Trying to call a function with invalid name", InterpretError::InvalidArgument => "Invalid argument for function", + InterpretError::ClosureBinOp => todo!(), + InterpretError::ClosureInvalidArg => todo!(), + InterpretError::ExpectedArg(_) => todo!(), }) } } type CalcFunction = Box Result>; +struct CalcFunctionImplement { + fun: CalcFunction, + args_type: Vec<&'static str>, +} struct FunctionRegistry { - functions: HashMap, + functions: HashMap, } impl FunctionRegistry { @@ -53,18 +76,34 @@ impl FunctionRegistry { } } - fn register(&mut self, name: &str, func: F) + fn register(&mut self, name: &str, func: F, args_types: Vec<&'static str>) where F: Fn(&[Interpret]) -> Result + 'static, { - self.functions.insert(name.to_string(), Box::new(func)); + let fun_insert = CalcFunctionImplement { + fun: Box::new(func), + args_type: args_types, + }; + self.functions.insert(name.to_string(), fun_insert); } fn call(&self, name: &str, args: &[Interpret]) -> Result { - self.functions + let function = self + .functions .get(name) - .ok_or(InterpretError::FunctionNotExist) - .and_then(|f| f(args)) + .ok_or(InterpretError::FunctionNotExist)?; + + if function.args_type.len() != args.len() { + return Err(InterpretError::InvalidArgument); + } + + for (expected_type, arg) in function.args_type.iter().zip(args) { + if *expected_type != arg.get_type() { + return Err(InterpretError::ExpectedArg(expected_type.to_string())); + } + } + + (function.fun)(args) } } @@ -81,6 +120,8 @@ fn count(args: &[Interpret]) -> Result { } Err(InterpretError::InvalidArgument) } + +//fn count_if(args: &[Interpret]) -> Result {} pub struct Interpreter<'a> { function_registry: FunctionRegistry, sheet: &'a Sheet, @@ -89,7 +130,7 @@ pub struct Interpreter<'a> { impl<'a> Interpreter<'a> { pub fn new(sheet: &'a Sheet) -> Self { let mut registry = FunctionRegistry::new(); - registry.register("count", count); + registry.register("count", count, vec!["Range"]); Self { function_registry: registry, sheet, @@ -206,6 +247,7 @@ impl<'a> Interpreter<'a> { None => Ok(Interpret::Text(i.to_string())), }, }, + Expr::Closure(closure) => Ok(Interpret::Closure(closure.clone())), } } @@ -235,6 +277,102 @@ impl Display for Interpret { .join(","), ), Interpret::Bool(b) => write!(f, "{}", b), + Interpret::Closure(_) => todo!(), } } } + +#[cfg(test)] +mod tests { + + use crate::calc::interpreter::Interpreter; + use crate::calc::parser::Parser; + use crate::{Cell, Sheet}; + + #[test] + fn test_range_inter() { + let mut sheet = Sheet::new(); + + sheet.insert( + (0, 0), + Cell { + val: crate::CellValue::Number(10.0), + format: crate::CellFormat {}, + }, + ); + + sheet.insert( + (0, 1), + Cell { + val: crate::CellValue::Number(20.0), + format: crate::CellFormat {}, + }, + ); + + let inter = Interpreter::new(&sheet); + + let expr = Parser::parse_string("(A1:A2)".to_string()).unwrap(); + let expr = inter.interpret(&expr).unwrap().to_string(); + + let expected = String::from("10,20"); + assert_eq!(expr, expected); + } + + #[test] + fn test_count() { + let mut sheet = Sheet::new(); + + sheet.insert( + (0, 0), + Cell { + val: crate::CellValue::Number(10.0), + format: crate::CellFormat {}, + }, + ); + + sheet.insert( + (0, 1), + Cell { + val: crate::CellValue::Number(20.0), + format: crate::CellFormat {}, + }, + ); + + let inter = Interpreter::new(&sheet); + + let expr = Parser::parse_string("count((A1:A2))".to_string()).unwrap(); + let expr = inter.interpret(&expr).unwrap().to_string(); + + let expected = String::from("30"); + assert_eq!(expr, expected); + } + + //[test] + //fn test_count_if() { + //let mut sheet = Sheet::new(); + + //sheet.insert( + //(0, 0), + //Cell { + //val: crate::CellValue::Number(10.0), + //format: crate::CellFormat {}, + //}, + //); + + //sheet.insert( + //(0, 1), + //Cell { + //val: crate::CellValue::Number(20.0), + //format: crate::CellFormat {}, + //}, + //); + + //let inter = Interpreter::new(&sheet); + + //let expr = Parser::parse_string("count_if(A1:A2, |v| v > 10)".to_string()).unwrap(); + //let expr = inter.interpret(&expr).unwrap().to_string(); + + //let expected = String::from("20"); + //assert_eq!(expr, expected); + //} +} diff --git a/src/calc/mod.rs b/src/calc/mod.rs index 667c632..3d339d6 100644 --- a/src/calc/mod.rs +++ b/src/calc/mod.rs @@ -25,6 +25,7 @@ pub enum Token { False, LeftParen, RightParen, + Bar, } impl Display for Token { @@ -49,6 +50,8 @@ impl Display for Token { Token::False => "FALSE", Token::LeftParen => "(", Token::RightParen => ")", + Token::EqualEqual => "==", + Token::Bar => "|", _ => unreachable!(), }), }; diff --git a/src/calc/parser.rs b/src/calc/parser.rs index f378c46..d215928 100644 --- a/src/calc/parser.rs +++ b/src/calc/parser.rs @@ -9,6 +9,7 @@ pub(crate) enum Expr { Range(Range), Call(Call), BinOp(BinOp), + Closure(Closure), Literal(Literal), } @@ -51,6 +52,12 @@ pub(crate) struct BinOp { pub(crate) right: BExpr, } +#[derive(PartialEq, Debug, Clone)] +pub(crate) struct Closure { + pub(crate) args: Vec, + pub(crate) body: BExpr, +} + #[derive(PartialEq, Debug, Clone)] pub(crate) struct Unary { pub(crate) operator: Token, @@ -170,6 +177,8 @@ impl Parser { fn parse_call(&mut self, callee: BExpr) -> Result { let mut args = Vec::new(); + dbg!(callee.clone()); + if !self.match_token(&Token::RightParen) { loop { args.push(self.parse_expression()?); @@ -184,8 +193,28 @@ impl Parser { Ok(Box::new(Expr::Call(Call { callee, args }))) } + fn parse_closure(&mut self) -> Result { + self.consume(&Token::Bar)?; + let mut args = Vec::new(); + + if !self.match_token(&Token::Bar) { + loop { + args.push(self.parse_expression()?); + if !self.match_token(&Token::Comma) { + break; + } + self.advance(); + } + } + + self.consume(&Token::Bar)?; + let expr = self.parse_expression()?; + Ok(Box::new(Expr::Closure(Closure { body: expr, args }))) + } + fn parse_primary(&mut self) -> Result, ParseError> { let mut expr = match self.tokens.peek() { + Some(Token::Bar) => self.parse_closure()?, Some(Token::Number(n)) => { let n = *n; self.advance(); @@ -210,12 +239,13 @@ impl Parser { self.consume(&Token::RightParen)?; expr } - _ => return Err(ParseError::ExpectedToken("Expression".to_string())), + token => { + dbg!(token); + return Err(ParseError::ExpectedToken("Expression".to_string())); + } }; while self.match_token(&Token::LeftParen) { - self.advance(); - expr = self.parse_call(expr)?; } @@ -225,17 +255,14 @@ impl Parser { #[cfg(test)] mod tests { - use crate::calc::interpreter::Interpreter; - use crate::{ - calc::{ - parser::{Call, Range}, - scanner::Scanner, - Token, - }, - Cell, Sheet, + + use crate::calc::{ + parser::{Call, Range}, + scanner::Scanner, + Token, }; - use super::{BExpr, BinOp, Expr, Literal, ParseError, Parser}; + use super::{BExpr, BinOp, Closure, Expr, Literal, ParseError, Parser}; fn parse_string(str: String) -> Result { let tokens = Scanner::new(str).scan(); @@ -281,60 +308,55 @@ mod tests { } #[test] - fn test_range_inter() { - let mut sheet = Sheet::new(); - - sheet.insert( - (0, 0), - Cell { - val: crate::CellValue::Number(10.0), - format: crate::CellFormat {}, - }, - ); - - sheet.insert( - (0, 1), - Cell { - val: crate::CellValue::Number(20.0), - format: crate::CellFormat {}, - }, - ); - - let inter = Interpreter::new(&sheet); - - let expr = parse_string("(A1:A2)".to_string()).unwrap(); - let expr = inter.interpret(&expr).unwrap().to_string(); - - let expected = String::from("10,20"); - assert_eq!(expr, expected); + fn test_call_range() { + let expr = parse_string("count(A1:A10)".to_string()).unwrap(); + let expected = Expr::Call(Call { + callee: Box::new(Expr::Literal(Literal::Identifier("count".to_string()))), + args: vec![Box::new(Expr::Range(Range { + from: Box::new(Expr::Literal(Literal::Identifier("A1".to_string()))), + to: Box::new(Expr::Literal(Literal::Identifier("A10".to_string()))), + }))], + }); + + assert_eq!(*expr, expected); } #[test] - fn test_count() { - let mut sheet = Sheet::new(); - - sheet.insert( - (0, 0), - Cell { - val: crate::CellValue::Number(10.0), - format: crate::CellFormat {}, - }, - ); - - sheet.insert( - (0, 1), - Cell { - val: crate::CellValue::Number(20.0), - format: crate::CellFormat {}, - }, - ); - - let inter = Interpreter::new(&sheet); - - let expr = parse_string("count((A1:A2))".to_string()).unwrap(); - let expr = inter.interpret(&expr).unwrap().to_string(); - - let expected = String::from("30"); - assert_eq!(expr, expected); + fn test_closure() { + let expr = Parser::parse_string("(|v| v > 2)".to_string()).unwrap(); + + let expected = Expr::Closure(Closure { + args: vec![Box::new(Expr::Literal(Literal::Identifier( + "v".to_string(), + )))], + body: Box::new(Expr::BinOp(BinOp { + left: Box::new(Expr::Literal(Literal::Identifier("v".to_string()))), + operator: Token::Greater, + right: Box::new(Expr::Literal(Literal::Number(2.0))), + })), + }); + + assert_eq!(*expr, expected); + } + + #[test] + fn test_closure_call() { + let expr = Parser::parse_string("count_if(|v| v > 2)".to_string()).unwrap(); + + let expected = Expr::Call(Call { + callee: Box::new(Expr::Literal(Literal::Identifier("count_if".to_string()))), + args: vec![Box::new(Expr::Closure(Closure { + args: vec![Box::new(Expr::Literal(Literal::Identifier( + "v".to_string(), + )))], + body: Box::new(Expr::BinOp(BinOp { + left: Box::new(Expr::Literal(Literal::Identifier("v".to_string()))), + operator: Token::Greater, + right: Box::new(Expr::Literal(Literal::Number(2.0))), + })), + }))], + }); + + assert_eq!(*expr, expected); } } diff --git a/src/calc/scanner.rs b/src/calc/scanner.rs index b64bc50..a2ff333 100644 --- a/src/calc/scanner.rs +++ b/src/calc/scanner.rs @@ -41,6 +41,7 @@ impl Scanner { ',' => Token::Comma, '.' => Token::Dot, ':' => Token::Colon, + '|' => Token::Bar, '=' if self.consume_if('=') => Token::EqualEqual, '>' if self.consume_if('=') => Token::GreaterEqual, '<' if self.consume_if('=') => Token::LessEqual, diff --git a/src/main.rs b/src/main.rs index f7dc04a..c226305 100644 --- a/src/main.rs +++ b/src/main.rs @@ -378,9 +378,17 @@ fn main() -> Result<()> { CellValue::Empty => CellValue::Empty, CellValue::Number(num) => { let old_num = num.to_string(); - CellValue::Number( - old_num[0..old_num.len() - 1].parse().unwrap(), - ) + + if !old_num.is_empty() { + old_num[0..old_num.len() - 1] + .parse::() + .map_or_else( + |_| CellValue::Text(old_num), + CellValue::Number, + ) + } else { + CellValue::Number(*num) + } } CellValue::Text(old) => { CellValue::Text(old[0..old.len() - 1].to_string()) @@ -408,15 +416,30 @@ fn main() -> Result<()> { CellValue::Empty => CellValue::Text(c.to_string()), CellValue::Number(num) => { let old_num = num.to_string(); - let last_digit = c.to_string().parse::().unwrap(); - CellValue::Number( - format!("{}{}", old_num, last_digit) - .parse() - .unwrap(), + c.to_string().parse::().map_or_else( + |_| { + CellValue::Text(format!( + "{}{}", + old_num.clone(), + c.clone() + )) + }, + |val| { + CellValue::Number( + format!("{}{}", old_num, val) + .parse() + .unwrap(), + ) + }, ) } CellValue::Text(old) => { - CellValue::Text(format!("{}{}", old, c)) + let value = format!("{}{}", old, c); + + value.parse::().map_or_else( + |_| CellValue::Text(value), + CellValue::Number, + ) } CellValue::Date(_) => todo!(), CellValue::Formula(_, _) => {