From 315478826f33e8788496ab774bcc462940be848c Mon Sep 17 00:00:00 2001 From: Roman Godmaire Date: Tue, 14 May 2024 13:45:38 -0400 Subject: [PATCH] feat: map function for iterators --- mute-interpreter/src/env/core.rs | 8 ++++---- mute-interpreter/src/evaluator.rs | 32 ++++++++++++++++++++++++++++++- mute-macros/src/lib.rs | 7 ++++++- mute-parser/src/lexer.rs | 9 +++++++++ mute-parser/src/lib.rs | 10 +++++++++- mute-parser/src/node.rs | 19 +++++++++++++++--- 6 files changed, 75 insertions(+), 10 deletions(-) diff --git a/mute-interpreter/src/env/core.rs b/mute-interpreter/src/env/core.rs index cc96452..532db68 100644 --- a/mute-interpreter/src/env/core.rs +++ b/mute-interpreter/src/env/core.rs @@ -214,7 +214,7 @@ pub(super) fn core() -> HashMap { .zip(values) .collect(); - Node::Map(res) + Node::Hashmap(res) }), ), ( @@ -222,7 +222,7 @@ pub(super) fn core() -> HashMap { NativeFunc(|args| { arg_count!(1, args.len()); - if let Node::Map(_map) = args[0].borrow() { + if let Node::Hashmap(_map) = args[0].borrow() { return Node::Boolean(true); } @@ -237,7 +237,7 @@ pub(super) fn core() -> HashMap { match args.pop_front().expect("argument length checked above") { Node::List(list) => Node::Boolean(list.is_empty()), Node::Vector(vec) => Node::Boolean(vec.is_empty()), - Node::Map(map) => Node::Boolean(map.is_empty()), + Node::Hashmap(map) => Node::Boolean(map.is_empty()), arg => Node::Error(format!( "TypeError: expected list, vector, or hashmap, got {}.", arg.get_type() @@ -253,7 +253,7 @@ pub(super) fn core() -> HashMap { match args.pop_front().expect("argument length checked above") { Node::List(list) => Node::Int(list.len() as i64), Node::Vector(vec) => Node::Int(vec.len() as i64), - Node::Map(map) => Node::Int(map.len() as i64), + Node::Hashmap(map) => Node::Int(map.len() as i64), arg => Node::Error(format!( "TypeError: expected list, vector, or hashmap, got {}.", arg.get_type() diff --git a/mute-interpreter/src/evaluator.rs b/mute-interpreter/src/evaluator.rs index e44c698..ec2a137 100644 --- a/mute-interpreter/src/evaluator.rs +++ b/mute-interpreter/src/evaluator.rs @@ -232,6 +232,36 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result { eval_node(env, Node::List(args))? } + Node::Map(mut body) => { + if body.len() != 2 { + return Err(Error::MismatchedArgCount(2, body.len())); + } + + let list = body.pop_front().expect("arg count verified above"); + let list = match eval_node(env, list)? { + Node::List(list) => list, + _ => todo!(), + }; + + let func = match body.pop_front().expect("arg count verified above") { + node @ Node::Function(_) => node, + _ => todo!(), + }; + + let list = list + .into_iter() + .map(|node| { + let expr = Node::List(vec![func.clone(), node].into()); + eval_node(env, expr) + }) + .collect::>>()?; + + Node::List(list) + } + Node::Filter(mut body) => todo!(), + Node::Reduce(mut body) => todo!(), + Node::Fold(mut body) => todo!(), + Node::Symbol(sym) => env .get_node(&sym) .ok_or_else(|| Error::NotInEnv(sym.clone()))? @@ -246,7 +276,7 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result { | Node::Void | Node::Error(_) | Node::Vector(_) - | Node::Map(_) + | Node::Hashmap(_) | Node::Function { .. } | Node::Macro { .. } => ast_node, }; diff --git a/mute-macros/src/lib.rs b/mute-macros/src/lib.rs index 08e884d..46423d7 100644 --- a/mute-macros/src/lib.rs +++ b/mute-macros/src/lib.rs @@ -32,7 +32,7 @@ fn format_node(node: Node) -> String { Node::Error(e) => format!("Node::Error(\"{e}\".to_string())"), Node::Vector(_) => todo!(), - Node::Map(_) => todo!(), + Node::Hashmap(_) => todo!(), // Quoting Node::Quote(node) => format!("Node::Quote(Box::new({}))", format_node(*node)), @@ -48,6 +48,11 @@ fn format_node(node: Node) -> String { Node::Do(body) => format!("Node::Do({})", reduce_list(body)), Node::Eval(body) => format!("Node::Eval({})", reduce_list(body)), Node::Apply(body) => format!("Node::Apply({})", reduce_list(body),), + + Node::Map(body) => format!("Node::Map({})", reduce_list(body)), + Node::Filter(body) => format!("Node::Filter({})", reduce_list(body)), + Node::Reduce(body) => format!("Node::Reduce({})", reduce_list(body)), + Node::Fold(body) => format!("Node::Fold({})", reduce_list(body)), } } diff --git a/mute-parser/src/lexer.rs b/mute-parser/src/lexer.rs index 13a84d0..662cd5f 100644 --- a/mute-parser/src/lexer.rs +++ b/mute-parser/src/lexer.rs @@ -44,6 +44,11 @@ pub enum Token { If, Do, + Map, + Filter, + Reduce, + Fold, + Quote, Quasiquote, Unquote, @@ -219,6 +224,10 @@ fn read_ident(input: &mut Peekable, first: char) -> Token { "apply" => Token::Apply, "if" => Token::If, "do" => Token::Do, + "map" => Token::Map, + "filter" => Token::Filter, + "reduce" => Token::Reduce, + "fold" => Token::Fold, ident => Token::Ident(ident.to_owned()), } } diff --git a/mute-parser/src/lib.rs b/mute-parser/src/lib.rs index 10ec180..5aacc30 100644 --- a/mute-parser/src/lib.rs +++ b/mute-parser/src/lib.rs @@ -40,6 +40,10 @@ fn next_statement(tokens: &mut TokenIter) -> Result> { Token::Apply => Node::Apply(read_body(tokens)?), Token::If => Node::If(read_body(tokens)?), Token::Do => Node::Do(read_body(tokens)?), + Token::Map => Node::Map(read_body(tokens)?), + Token::Filter => Node::Filter(read_body(tokens)?), + Token::Reduce => Node::Reduce(read_body(tokens)?), + Token::Fold => Node::Fold(read_body(tokens)?), _ => read_list(tokens, Token::RightParen)?, }, @@ -82,7 +86,11 @@ fn next_statement(tokens: &mut TokenIter) -> Result> { | Token::Eval | Token::Apply | Token::If - | Token::Do => Err(Error::SpecialNotOperator)?, + | Token::Do + | Token::Map + | Token::Filter + | Token::Reduce + | Token::Fold => Err(Error::SpecialNotOperator)?, }; Ok(Some(node)) diff --git a/mute-parser/src/node.rs b/mute-parser/src/node.rs index 284655b..b1073c2 100644 --- a/mute-parser/src/node.rs +++ b/mute-parser/src/node.rs @@ -16,7 +16,7 @@ pub enum Node { Error(String), Vector(Vec), - Map(HashMap), + Hashmap(HashMap), // Specials // TODO: Specials should point to a LinkedList @@ -33,6 +33,11 @@ pub enum Node { Do(VecDeque), Eval(VecDeque), Apply(VecDeque), + + Map(VecDeque), + Filter(VecDeque), + Reduce(VecDeque), + Fold(VecDeque), } impl Node { @@ -49,7 +54,7 @@ impl Node { Node::Void => "void".to_string(), Node::Error(_) => "error".to_string(), Node::Vector(_) => "vector".to_string(), - Node::Map(_) => "map".to_string(), + Node::Hashmap(_) => "hashmap".to_string(), Node::Define { .. } => "define".to_string(), Node::Let { .. } => "let".to_string(), Node::Function { .. } => "function".to_string(), @@ -61,6 +66,10 @@ impl Node { Node::Do { .. } => "do".to_string(), Node::Eval { .. } => "eval".to_string(), Node::Apply { .. } => "apply".to_string(), + Node::Map { .. } => "map".to_string(), + Node::Filter { .. } => "filter".to_string(), + Node::Reduce { .. } => "reduce".to_string(), + Node::Fold { .. } => "fold".to_string(), } } } @@ -91,7 +100,7 @@ impl std::fmt::Display for Node { Node::Error(val) => write!(f, "error: {}", val), Node::Vector(body) => write!(f, "[{}]", reduce_list(body)), - Node::Map(body) => write!( + Node::Hashmap(body) => write!( f, "{{{}}}", body.iter() @@ -113,6 +122,10 @@ impl std::fmt::Display for Node { Node::Do(body) => write!(f, "(do {})", reduce_list(body)), Node::Eval(body) => write!(f, "(eval {})", reduce_list(body)), Node::Apply(body) => write!(f, "(apply {})", reduce_list(body)), + Node::Map(body) => write!(f, "(map {})", reduce_list(body)), + Node::Filter(body) => write!(f, "(filter {})", reduce_list(body)), + Node::Reduce(body) => write!(f, "(reduce {})", reduce_list(body)), + Node::Fold(body) => write!(f, "(fold {})", reduce_list(body)), } } }