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)
.collect();
Node::Map(res)
Node::Hashmap(res)
}),
),
(
@ -222,7 +222,7 @@ pub(super) fn core() -> HashMap<String, Value> {
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<String, Value> {
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<String, Value> {
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()

View file

@ -232,6 +232,36 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
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
.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> {
| Node::Void
| Node::Error(_)
| Node::Vector(_)
| Node::Map(_)
| Node::Hashmap(_)
| Node::Function { .. }
| 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::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)),
}
}

View file

@ -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<Chars>, 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()),
}
}

View file

@ -40,6 +40,10 @@ fn next_statement(tokens: &mut TokenIter) -> Result<Option<Node>> {
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<Option<Node>> {
| 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))

View file

@ -16,7 +16,7 @@ pub enum Node {
Error(String),
Vector(Vec<Node>),
Map(HashMap<String, Node>),
Hashmap(HashMap<String, Node>),
// Specials
// TODO: Specials should point to a LinkedList
@ -33,6 +33,11 @@ pub enum Node {
Do(VecDeque<Node>),
Eval(VecDeque<Node>),
Apply(VecDeque<Node>),
Map(VecDeque<Node>),
Filter(VecDeque<Node>),
Reduce(VecDeque<Node>),
Fold(VecDeque<Node>),
}
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)),
}
}
}