feat: map function for iterators

This commit is contained in:
Roman Godmaire 2024-05-14 13:45:38 -04:00
parent a7c6e1a07d
commit 315478826f
6 changed files with 75 additions and 10 deletions

View file

@ -214,7 +214,7 @@ pub(super) fn core() -> HashMap<String, Value> {
.zip(values) .zip(values)
.collect(); .collect();
Node::Map(res) Node::Hashmap(res)
}), }),
), ),
( (
@ -222,7 +222,7 @@ pub(super) fn core() -> HashMap<String, Value> {
NativeFunc(|args| { NativeFunc(|args| {
arg_count!(1, args.len()); 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); return Node::Boolean(true);
} }
@ -237,7 +237,7 @@ pub(super) fn core() -> HashMap<String, Value> {
match args.pop_front().expect("argument length checked above") { match args.pop_front().expect("argument length checked above") {
Node::List(list) => Node::Boolean(list.is_empty()), Node::List(list) => Node::Boolean(list.is_empty()),
Node::Vector(vec) => Node::Boolean(vec.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!( arg => Node::Error(format!(
"TypeError: expected list, vector, or hashmap, got {}.", "TypeError: expected list, vector, or hashmap, got {}.",
arg.get_type() arg.get_type()
@ -253,7 +253,7 @@ pub(super) fn core() -> HashMap<String, Value> {
match args.pop_front().expect("argument length checked above") { match args.pop_front().expect("argument length checked above") {
Node::List(list) => Node::Int(list.len() as i64), Node::List(list) => Node::Int(list.len() as i64),
Node::Vector(vec) => Node::Int(vec.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!( arg => Node::Error(format!(
"TypeError: expected list, vector, or hashmap, got {}.", "TypeError: expected list, vector, or hashmap, got {}.",
arg.get_type() arg.get_type()

View file

@ -232,6 +232,36 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
eval_node(env, Node::List(args))? 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::<Result<VecDeque<Node>>>()?;
Node::List(list)
}
Node::Filter(mut body) => todo!(),
Node::Reduce(mut body) => todo!(),
Node::Fold(mut body) => todo!(),
Node::Symbol(sym) => env Node::Symbol(sym) => env
.get_node(&sym) .get_node(&sym)
.ok_or_else(|| Error::NotInEnv(sym.clone()))? .ok_or_else(|| Error::NotInEnv(sym.clone()))?
@ -246,7 +276,7 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
| Node::Void | Node::Void
| Node::Error(_) | Node::Error(_)
| Node::Vector(_) | Node::Vector(_)
| Node::Map(_) | Node::Hashmap(_)
| Node::Function { .. } | Node::Function { .. }
| Node::Macro { .. } => ast_node, | Node::Macro { .. } => ast_node,
}; };

View file

@ -32,7 +32,7 @@ fn format_node(node: Node) -> String {
Node::Error(e) => format!("Node::Error(\"{e}\".to_string())"), Node::Error(e) => format!("Node::Error(\"{e}\".to_string())"),
Node::Vector(_) => todo!(), Node::Vector(_) => todo!(),
Node::Map(_) => todo!(), Node::Hashmap(_) => todo!(),
// Quoting // Quoting
Node::Quote(node) => format!("Node::Quote(Box::new({}))", format_node(*node)), 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::Do(body) => format!("Node::Do({})", reduce_list(body)),
Node::Eval(body) => format!("Node::Eval({})", reduce_list(body)), Node::Eval(body) => format!("Node::Eval({})", reduce_list(body)),
Node::Apply(body) => format!("Node::Apply({})", 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)),
} }
} }

View file

@ -44,6 +44,11 @@ pub enum Token {
If, If,
Do, Do,
Map,
Filter,
Reduce,
Fold,
Quote, Quote,
Quasiquote, Quasiquote,
Unquote, Unquote,
@ -219,6 +224,10 @@ fn read_ident(input: &mut Peekable<Chars>, first: char) -> Token {
"apply" => Token::Apply, "apply" => Token::Apply,
"if" => Token::If, "if" => Token::If,
"do" => Token::Do, "do" => Token::Do,
"map" => Token::Map,
"filter" => Token::Filter,
"reduce" => Token::Reduce,
"fold" => Token::Fold,
ident => Token::Ident(ident.to_owned()), ident => Token::Ident(ident.to_owned()),
} }
} }

View file

@ -40,6 +40,10 @@ fn next_statement(tokens: &mut TokenIter) -> Result<Option<Node>> {
Token::Apply => Node::Apply(read_body(tokens)?), Token::Apply => Node::Apply(read_body(tokens)?),
Token::If => Node::If(read_body(tokens)?), Token::If => Node::If(read_body(tokens)?),
Token::Do => Node::Do(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)?, _ => read_list(tokens, Token::RightParen)?,
}, },
@ -82,7 +86,11 @@ fn next_statement(tokens: &mut TokenIter) -> Result<Option<Node>> {
| Token::Eval | Token::Eval
| Token::Apply | Token::Apply
| Token::If | Token::If
| Token::Do => Err(Error::SpecialNotOperator)?, | Token::Do
| Token::Map
| Token::Filter
| Token::Reduce
| Token::Fold => Err(Error::SpecialNotOperator)?,
}; };
Ok(Some(node)) Ok(Some(node))

View file

@ -16,7 +16,7 @@ pub enum Node {
Error(String), Error(String),
Vector(Vec<Node>), Vector(Vec<Node>),
Map(HashMap<String, Node>), Hashmap(HashMap<String, Node>),
// Specials // Specials
// TODO: Specials should point to a LinkedList // TODO: Specials should point to a LinkedList
@ -33,6 +33,11 @@ pub enum Node {
Do(VecDeque<Node>), Do(VecDeque<Node>),
Eval(VecDeque<Node>), Eval(VecDeque<Node>),
Apply(VecDeque<Node>), Apply(VecDeque<Node>),
Map(VecDeque<Node>),
Filter(VecDeque<Node>),
Reduce(VecDeque<Node>),
Fold(VecDeque<Node>),
} }
impl Node { impl Node {
@ -49,7 +54,7 @@ impl Node {
Node::Void => "void".to_string(), Node::Void => "void".to_string(),
Node::Error(_) => "error".to_string(), Node::Error(_) => "error".to_string(),
Node::Vector(_) => "vector".to_string(), Node::Vector(_) => "vector".to_string(),
Node::Map(_) => "map".to_string(), Node::Hashmap(_) => "hashmap".to_string(),
Node::Define { .. } => "define".to_string(), Node::Define { .. } => "define".to_string(),
Node::Let { .. } => "let".to_string(), Node::Let { .. } => "let".to_string(),
Node::Function { .. } => "function".to_string(), Node::Function { .. } => "function".to_string(),
@ -61,6 +66,10 @@ impl Node {
Node::Do { .. } => "do".to_string(), Node::Do { .. } => "do".to_string(),
Node::Eval { .. } => "eval".to_string(), Node::Eval { .. } => "eval".to_string(),
Node::Apply { .. } => "apply".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::Error(val) => write!(f, "error: {}", val),
Node::Vector(body) => write!(f, "[{}]", reduce_list(body)), Node::Vector(body) => write!(f, "[{}]", reduce_list(body)),
Node::Map(body) => write!( Node::Hashmap(body) => write!(
f, f,
"{{{}}}", "{{{}}}",
body.iter() body.iter()
@ -113,6 +122,10 @@ impl std::fmt::Display for Node {
Node::Do(body) => write!(f, "(do {})", reduce_list(body)), Node::Do(body) => write!(f, "(do {})", reduce_list(body)),
Node::Eval(body) => write!(f, "(eval {})", reduce_list(body)), Node::Eval(body) => write!(f, "(eval {})", reduce_list(body)),
Node::Apply(body) => write!(f, "(apply {})", 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)),
} }
} }
} }