Skip to content

Commit

Permalink
Add dotted pair
Browse files Browse the repository at this point in the history
  • Loading branch information
vinc committed Oct 28, 2022
1 parent 40981ee commit 10544b5
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 3 deletions.
7 changes: 5 additions & 2 deletions src/usr/lisp/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ pub fn expand(exp: &Exp, env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
match (&list[1], &list[2]) {
(Exp::List(args), Exp::List(_)) => {
ensure_length_gt!(args, 0);
let name = args[0].clone();
let args = Exp::List(args[1..].to_vec());
let (name, args) = if args.len() == 3 && args[0] == Exp::Sym("cons".to_string()) {
(args[1].clone(), args[2].clone())
} else {
(args[0].clone(), Exp::List(args[1..].to_vec()))
};
let body = expand(&list[2], env)?;
Ok(Exp::List(vec![
Exp::Sym("define".to_string()), name, Exp::List(vec![
Expand Down
9 changes: 9 additions & 0 deletions src/usr/lisp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,16 @@ fn test_lisp() {
eval!("(set-10 foo)");
assert_eq!(eval!("foo"), "10");

// dotted pair
assert_eq!(eval!("(cons 1 (cons 2 (cons 3 '())))"), "(1 2 3)");
assert_eq!(eval!("(cons 1 (2 . (3 . '())))"), "(1 2 3)");
assert_eq!(eval!("(cons 1 (list 2 3))"), "(1 2 3)");
assert_eq!(eval!("'(cons 1 (cons 2 (cons 3 '())))"), "(cons 1 (cons 2 (cons 3 (quote ()))))");
assert_eq!(eval!("'(1 . (2 . (3 . '())))"), "(cons 1 (cons 2 (cons 3 (quote ()))))");

// args
eval!("(define list* (function args (append args '())))");
assert_eq!(eval!("(list* 1 2 3)"), "(1 2 3)");
eval!("(define (list* . args) (append args '())))");
assert_eq!(eval!("(list* 1 2 3)"), "(1 2 3)");
}
14 changes: 13 additions & 1 deletion src/usr/lisp/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use nom::multi::many0;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::tuple;
use nom::sequence::separated_pair;

fn is_symbol_letter(c: char) -> bool {
let chars = "<>=-+*/%^?:";
Expand Down Expand Up @@ -61,6 +62,16 @@ fn parse_list(input: &str) -> IResult<&str, Exp> {
Ok((input, Exp::List(list)))
}

fn parse_pair(input: &str) -> IResult<&str, Exp> {
let (input, (car, cdr)) = delimited(
char('('),
separated_pair(parse_exp, char('.'), parse_exp),
char(')')
)(input)?;
let list = vec![Exp::Sym("cons".to_string()), car, cdr];
Ok((input, Exp::List(list)))
}

fn parse_quote(input: &str) -> IResult<&str, Exp> {
let (input, list) = preceded(char('\''), parse_exp)(input)?;
let list = vec![Exp::Sym("quote".to_string()), list];
Expand All @@ -87,7 +98,8 @@ fn parse_quasiquote(input: &str) -> IResult<&str, Exp> {

fn parse_exp(input: &str) -> IResult<&str, Exp> {
delimited(multispace0, alt((
parse_num, parse_bool, parse_str, parse_list, parse_quote, parse_unquote_splicing, parse_unquote, parse_quasiquote, parse_sym
parse_num, parse_bool, parse_str, parse_list, parse_pair, parse_quote,
parse_unquote_splicing, parse_unquote, parse_quasiquote, parse_sym
)), multispace0)(input)
}

Expand Down

0 comments on commit 10544b5

Please sign in to comment.