Adding car and cdr functions

This commit is contained in:
teo3300
2024-05-24 18:43:43 +09:00
parent 06adb25362
commit 97f1bd8d82
4 changed files with 31 additions and 1 deletions

View File

@ -1,6 +1,8 @@
use std::{cell::RefCell, env, rc::Rc};
use crate::env::{any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_exit, Env};
use crate::env::{
any_zero, arithmetic_op, car, comparison_op, env_new, env_set, mal_car, mal_cdr, mal_exit, Env,
};
// This is the first time I implement a macro, and I'm copying it
// so I will comment this a LOT
@ -59,6 +61,8 @@ pub fn ns_init() -> Env {
"type" => Fun(|a| Ok(car(a)?.label_type()), "Returns a label indicating the type of it's argument"),
"count" => Fun(|a| Ok(Int(car(a)?.if_list()?.len() as isize)), "Return the number of elements in the first argument"),
"=" => Fun(mal_equals, "Return true if the first two parameters are the same type and content, in case of lists propagate to all elements (NOT IMPLEMENTED for 'Map', 'Fun' and 'MalFun')"),
"car" => Fun(|a| mal_car(car(a)?), "Returns the first element of the list, NIL if its empty"),
"cdr" => Fun(|a| mal_cdr(car(a)?), "Returns all the list but the first element"),
"assert" => Fun(mal_assert, "Return an error if assertion fails"),
"read-string" => Fun(|a| read_str(Reader::new().push(car(a)?.if_string()?)).map_err(MalErr::severe), "Tokenize and read the first argument"),
"slurp" => Fun(|a| Ok(Str(read_file(car(a)?.if_string()?)?)), "Read a file and return the content as a string"),

View File

@ -170,6 +170,20 @@ pub fn cdr(list: &[MalType]) -> &[MalType] {
}
}
pub fn mal_cdr(arg: &MalType) -> MalRet {
let list = arg.if_list()?;
Ok(MalType::List(cdr(list).into()))
}
pub fn mal_car(arg: &MalType) -> MalRet {
let list = arg.if_list()?;
if list.is_empty() {
Ok(Nil)
} else {
Ok(list[0].clone())
}
}
/// Extract the car and cdr from a list
pub fn car_cdr(list: &[MalType]) -> Result<(&MalType, &[MalType]), MalErr> {
Ok((car(list)?, cdr(list)))

View File

@ -55,4 +55,9 @@ mod functional {
fn atoms() {
test!("atoms")
}
#[test]
fn car_cdr() {
test!("car-cdr")
}
}

7
tests/car-cdr.mal Normal file
View File

@ -0,0 +1,7 @@
;; Test car
(assert-eq (car '(1 2 3)) 1)
(assert-eq (car '()) nil)
;; Test cdr
(assert-eq (cdr '(1 2 3)) '(2 3))
(assert-eq (cdr '()) '())