mirror of
https://github.com/teo3300/rust-mal.git
synced 2026-01-12 01:05:32 +01:00
Adding map for HOF
This commit is contained in:
4
Makefile
4
Makefile
@ -6,8 +6,10 @@ build-release:
|
||||
test:
|
||||
cargo test --release
|
||||
|
||||
install: build-release
|
||||
conf:
|
||||
mkdir -p ${HOME}/.config/mal
|
||||
cp -f core/core.mal ${HOME}/.config/mal/
|
||||
|
||||
install: build-release conf
|
||||
sudo cp target/release/rust-mal /usr/local/bin/mal
|
||||
sudo chown ${USER} /usr/local/bin/mal
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use std::{cell::RefCell, env, rc::Rc};
|
||||
|
||||
use crate::env::{
|
||||
any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_car, mal_cdr, mal_exit, Env,
|
||||
any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_car, mal_cdr, mal_exit,
|
||||
mal_map, Env,
|
||||
};
|
||||
|
||||
// This is the first time I implement a macro, and I'm copying it
|
||||
@ -80,6 +81,7 @@ pub fn ns_init() -> Env {
|
||||
"atom" => Fun(|a| Ok(Atom(Rc::new(RefCell::new(car(a).unwrap_or_default().clone())))), "Return an atom pointing to the given arg"),
|
||||
"deref" => Fun(|a| if_atom!(car(a)?), "Return the content of the atom argumet"),
|
||||
"reset!" => Fun(reset_bang, "Change the value of the Atom (frist argument) to the second argument"),
|
||||
"map" => Fun(mal_map, "Apply the first argument to all the elements of the second arguments"),
|
||||
"env" => Fun(|a| match env::var(car(a)?.if_string()?) {
|
||||
Ok(s) => Ok(Str(s.into())),
|
||||
_ => Ok(Nil),
|
||||
|
||||
32
src/env.rs
32
src/env.rs
@ -189,6 +189,38 @@ pub fn car_cdr(list: &[MalType]) -> Result<(&MalType, &[MalType]), MalErr> {
|
||||
Ok((car(list)?, cdr(list)))
|
||||
}
|
||||
|
||||
pub fn mal_map(args: &[MalType]) -> MalRet {
|
||||
let mut ret = Vec::new();
|
||||
let (lambda, list) = car_cdr(args)?;
|
||||
let list = car(list)?.if_list()?;
|
||||
match lambda {
|
||||
M::Fun(func, _) => {
|
||||
for el in list {
|
||||
ret.push(func(&[el.clone()])?);
|
||||
}
|
||||
}
|
||||
M::MalFun {
|
||||
params, ast, env, ..
|
||||
} => {
|
||||
for el in list {
|
||||
let inner_env = env_binds(env.clone(), params, &[el.clone()])?;
|
||||
match ast.as_ref() {
|
||||
M::List(ops) => {
|
||||
let mut last = MalType::Nil;
|
||||
for x in &ops[0..ops.len()] {
|
||||
last = eval(x, inner_env.clone())?;
|
||||
}
|
||||
ret.push(last)
|
||||
}
|
||||
_ => scream!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => scream!(),
|
||||
};
|
||||
Ok(MalType::List(ret.into()))
|
||||
}
|
||||
|
||||
fn first(list: &[MalType]) -> &[MalType] {
|
||||
if list.len() > 1 {
|
||||
&list[..list.len() - 1]
|
||||
|
||||
@ -60,4 +60,9 @@ mod functional {
|
||||
fn car_cdr() {
|
||||
test!("car-cdr")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map() {
|
||||
test!("map")
|
||||
}
|
||||
}
|
||||
|
||||
5
tests/map.mal
Normal file
5
tests/map.mal
Normal file
@ -0,0 +1,5 @@
|
||||
; builtin map
|
||||
(assert-eq '((1) (2) (3)) (map list '(1 2 3)))
|
||||
|
||||
; lambda map
|
||||
(assert-eq '(2 3 4) (map (fn* [x] (+ x 1)) '(1 2 3)))
|
||||
Reference in New Issue
Block a user