diff --git a/userspace/lib/lysp/src/parse.rs b/userspace/lib/lysp/src/parse.rs index 1b7d0012..0e863d8e 100644 --- a/userspace/lib/lysp/src/parse.rs +++ b/userspace/lib/lysp/src/parse.rs @@ -11,7 +11,7 @@ use nom::{ combinator::{map, map_res, opt, recognize, value, verify}, error::{Error, ErrorKind, FromExternalError, ParseError}, multi::{fold, fold_many1, many0}, - sequence::{delimited, preceded}, + sequence::{delimited, pair, preceded}, }; use crate::vm::value::{Keyword, NumberValue, Value, Vector}; @@ -331,8 +331,25 @@ fn parse_vector(input: &str) -> IResult<&str, Value> { .parse(input) } +fn parse_dotted_cons(input: &str) -> IResult<&str, Value> { + delimited( + char('('), + pair( + preceded(skip_comment_and_whitespace, parse_value), + preceded( + pair(skip_comment_and_whitespace, char('.')), + preceded(skip_comment_and_whitespace, parse_value), + ), + ), + preceded(skip_comment_and_whitespace, char(')')), + ) + .map(|(a, b)| a.cons(b)) + .parse(input) +} + pub fn parse_value(input: &str) -> IResult<&str, Value> { alt(( + parse_dotted_cons, parse_list_or_nil, parse_vector, parse_boolean, @@ -353,9 +370,9 @@ mod tests { use crate::{ parse::{ - OverflowError, parse_boolean, parse_identifier, parse_identifier_or_keyword_or_nil, - parse_integer, parse_integer_dec, parse_integer_hex, parse_integer_oct, - parse_list_or_nil, parse_value, + OverflowError, parse_boolean, parse_dotted_cons, parse_identifier, + parse_identifier_or_keyword_or_nil, parse_integer, parse_integer_dec, + parse_integer_hex, parse_integer_oct, parse_list_or_nil, parse_value, }, vm::value::{Keyword, Value}, }; @@ -514,6 +531,27 @@ mod tests { assert_eq!(v, Value::Boolean(false.into())); } + #[test] + fn test_dotted_pair() { + let (r, v) = parse_dotted_cons("(a.b)").unwrap(); + assert_eq!(r, ""); + assert_eq!( + v, + Value::Identifier("a".into()).cons(Value::Identifier("b".into())) + ); + let (r, v) = parse_dotted_cons("(a .(b. ( c . (d.NIL ) )))").unwrap(); + assert_eq!(r, ""); + assert_eq!( + v, + Value::list_or_nil([ + Value::Identifier("a".into()), + Value::Identifier("b".into()), + Value::Identifier("c".into()), + Value::Identifier("d".into()), + ]) + ); + } + #[test] fn test_value() { let (r, v) = parse_value("+123\n").unwrap(); diff --git a/userspace/lib/lysp/src/vm/machine.rs b/userspace/lib/lysp/src/vm/machine.rs index 0c777488..f67101a6 100644 --- a/userspace/lib/lysp/src/vm/machine.rs +++ b/userspace/lib/lysp/src/vm/machine.rs @@ -857,6 +857,7 @@ mod tests { let env = Rc::new(Environment::default()); // (lambda (y) (let (x 123) (+ x y))) let lambda_function = Rc::new(BytecodeFunction { + script: None, identifier: None, docstring: None, instructions: [ @@ -906,6 +907,7 @@ mod tests { let env = Rc::new(Environment::default()); // (lambda (x y) (+ x y)) let lambda_function = Rc::new(BytecodeFunction { + script: None, identifier: None, docstring: None, instructions: [