diff --git a/src/eval/tests/mod.rs b/src/eval/tests/mod.rs index 089feed7ea..7f3069196f 100644 --- a/src/eval/tests/mod.rs +++ b/src/eval/tests/mod.rs @@ -2347,11 +2347,17 @@ fn test_sym_hash_values() { let s = &mut Store::::default(); let state = State::init_lurk_state().mutable(); - let asdf_sym_package_name = state.borrow_mut().intern_path(&["asdf"], false).unwrap(); + let asdf_sym_package_name = state + .borrow_mut() + .intern_path(&["asdf"], false, false) + .unwrap(); let asdf_sym_package = Package::new(asdf_sym_package_name.into()); state.borrow_mut().add_package(asdf_sym_package); - let asdf_key_package_name = state.borrow_mut().intern_path(&["asdf"], true).unwrap(); + let asdf_key_package_name = state + .borrow_mut() + .intern_path(&["asdf"], true, false) + .unwrap(); let asdf_key_package = Package::new(asdf_key_package_name.into()); state.borrow_mut().add_package(asdf_key_package); diff --git a/src/lem/eval.rs b/src/lem/eval.rs index 985793f0f8..724635d0b8 100644 --- a/src/lem/eval.rs +++ b/src/lem/eval.rs @@ -862,39 +862,32 @@ mod tests { fn expr_in_expr_out_pairs(s: &mut Store) -> Vec<(Ptr, Ptr)> { let state = State::init_lurk_state().mutable(); - let sum = s.read(state.clone(), "(+ 21 21)").unwrap(); - let sum_res = s.read(state.clone(), "42").unwrap(); - let car = s.read(state.clone(), "(car (cons 1 2))").unwrap(); - let car_res = s.read(state.clone(), "1").unwrap(); - let let_ = s - .read( - state.clone(), - "(let ((x (cons 1 2))) - (cons (car x) (cdr x)))", - ) - .unwrap(); - let let_res = s.read(state.clone(), "(1 . 2)").unwrap(); - let lam0 = s.read(state.clone(), "((lambda () 1))").unwrap(); - let lam0_res = s.read(state.clone(), "1").unwrap(); - let lam = s - .read(state.clone(), "((lambda (x y) (+ x y)) 3 4)") - .unwrap(); - let lam_res = s.read(state.clone(), "7").unwrap(); - let fold = s - .read( - state.clone(), - "(letrec ((build (lambda (x) - (if (eq x 0) - nil - (cons x (build (- x 1)))))) - (sum (lambda (xs) - (if (eq xs nil) - 0 - (+ (car xs) (sum (cdr xs))))))) - (sum (build 10)))", - ) - .unwrap(); - let fold_res = s.read(state, "55").unwrap(); + let mut read = |code: &str| s.read(state.clone(), code).unwrap(); + let sum = read("(+ 21 21)"); + let sum_res = read("42"); + let car = read("(car (cons 1 2))"); + let car_res = read("1"); + let let_ = read( + "(let ((x (cons 1 2))) + (cons (car x) (cdr x)))", + ); + let let_res = read("(1 . 2)"); + let lam0 = read("((lambda () 1))"); + let lam0_res = read("1"); + let lam = read("((lambda (x y) (+ x y)) 3 4)"); + let lam_res = read("7"); + let fold = read( + "(letrec ((build (lambda (x) + (if (eq x 0) + nil + (cons x (build (- x 1)))))) + (sum (lambda (xs) + (if (eq xs nil) + 0 + (+ (car xs) (sum (cdr xs))))))) + (sum (build 10)))", + ); + let fold_res = read("55"); vec![ (sum, sum_res), (car, car_res), diff --git a/src/lem/store.rs b/src/lem/store.rs index 2a5b39819a..e662c7ff0b 100644 --- a/src/lem/store.rs +++ b/src/lem/store.rs @@ -262,8 +262,11 @@ impl Store { use crate::parser::*; use nom::sequence::preceded; use nom::Parser; - match preceded(syntax::parse_space, syntax::parse_syntax(state, false)) - .parse(Span::new(input)) + match preceded( + syntax::parse_space, + syntax::parse_syntax(state, false, false), + ) + .parse(Span::new(input)) { Ok((_i, x)) => self.intern_syntax(x), Err(e) => bail!("{}", e), diff --git a/src/parser.rs b/src/parser.rs index fb88cbb2ab..8e67ef16d1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -37,8 +37,11 @@ pub enum Error { impl Store { pub fn read(&mut self, input: &str) -> Result, Error> { let state = State::init_lurk_state().mutable(); - match preceded(syntax::parse_space, syntax::parse_syntax(state, false)) - .parse(Span::new(input)) + match preceded( + syntax::parse_space, + syntax::parse_syntax(state, false, false), + ) + .parse(Span::new(input)) { Ok((_i, x)) => Ok(self.intern_syntax(x)), Err(e) => Err(Error::Syntax(format!("{}", e))), @@ -50,8 +53,11 @@ impl Store { state: Rc>, input: &str, ) -> Result, Error> { - match preceded(syntax::parse_space, syntax::parse_syntax(state, false)) - .parse(Span::new(input)) + match preceded( + syntax::parse_space, + syntax::parse_syntax(state, false, false), + ) + .parse(Span::new(input)) { Ok((_i, x)) => Ok(self.intern_syntax(x)), Err(e) => Err(Error::Syntax(format!("{}", e))), @@ -64,7 +70,7 @@ impl Store { input: Span<'a>, ) -> Result<(Span<'a>, Ptr, bool), Error> { use syntax::*; - match preceded(parse_space, parse_maybe_meta(state)).parse(input) { + match preceded(parse_space, parse_maybe_meta(state, false)).parse(input) { Ok((i, Some((is_meta, x)))) => Ok((i, self.intern_syntax(x), is_meta)), Ok((_, None)) => Err(Error::NoInput), Err(e) => Err(Error::Syntax(format!("{}", e))), diff --git a/src/parser/syntax.rs b/src/parser/syntax.rs index 25e44e6258..f8c3552df0 100644 --- a/src/parser/syntax.rs +++ b/src/parser/syntax.rs @@ -94,17 +94,26 @@ fn intern_path<'a, F: LurkField>( upto: LocatedSpan<&'a str>, path: &[String], keyword: Option, + create_unknown_packages: bool, ) -> ParseResult<'a, F, SymbolRef> { use nom::Err::Failure; match keyword { - Some(keyword) => match state.borrow_mut().intern_path(path, keyword) { - Ok(symbol) => Ok((upto, symbol)), - Err(e) => Err(Failure(ParseError::new( - upto, - ParseErrorKind::InterningError(format!("{e}")), - ))), - }, - None => match state.borrow_mut().intern_relative_path(path) { + Some(keyword) => { + match state + .borrow_mut() + .intern_path(path, keyword, create_unknown_packages) + { + Ok(symbol) => Ok((upto, symbol)), + Err(e) => Err(Failure(ParseError::new( + upto, + ParseErrorKind::InterningError(format!("{e}")), + ))), + } + } + None => match state + .borrow_mut() + .intern_relative_path(path, create_unknown_packages) + { Ok(symbol) => Ok((upto, symbol)), Err(e) => Err(Failure(ParseError::new( upto, @@ -116,6 +125,7 @@ fn intern_path<'a, F: LurkField>( pub fn parse_absolute_symbol( state: Rc>, + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, SymbolRef> { move |from: Span<'_>| { let (i, is_key) = alt(( @@ -123,41 +133,62 @@ pub fn parse_absolute_symbol( value(true, char(symbol::KEYWORD_MARKER)), ))(from)?; let (upto, path) = parse_symbol_limbs()(i)?; - intern_path(state.clone(), upto, &path, Some(is_key)) + intern_path( + state.clone(), + upto, + &path, + Some(is_key), + create_unknown_packages, + ) } } pub fn parse_relative_symbol( state: Rc>, + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, SymbolRef> { move |from: Span<'_>| { let (i, _) = peek(none_of(",~#(){}[]1234567890."))(from)?; let (upto, path) = parse_symbol_limbs()(i)?; - intern_path(state.clone(), upto, &path, None) + intern_path(state.clone(), upto, &path, None, create_unknown_packages) } } pub fn parse_raw_symbol( state: Rc>, + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, SymbolRef> { move |from: Span<'_>| { let (i, _) = tag("~(")(from)?; let (i, mut path) = many0(preceded(parse_space, parse_symbol_limb_raw("|()")))(i)?; let (upto, _) = many_till(parse_space, tag(")"))(i)?; path.reverse(); - intern_path(state.clone(), upto, &path, Some(false)) + intern_path( + state.clone(), + upto, + &path, + Some(false), + create_unknown_packages, + ) } } pub fn parse_raw_keyword( state: Rc>, + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, SymbolRef> { move |from: Span<'_>| { let (i, _) = tag("~:(")(from)?; let (i, mut path) = many0(preceded(parse_space, parse_symbol_limb_raw("|()")))(i)?; let (upto, _) = many_till(parse_space, tag(")"))(i)?; path.reverse(); - intern_path(state.clone(), upto, &path, Some(true)) + intern_path( + state.clone(), + upto, + &path, + Some(true), + create_unknown_packages, + ) } } @@ -167,13 +198,14 @@ pub fn parse_raw_keyword( /// raw keyword: ~:(foo bar) = :bar.foo pub fn parse_symbol( state: Rc>, + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, Syntax> { move |from: Span<'_>| { let (upto, sym) = alt(( - parse_raw_symbol(state.clone()), - parse_raw_keyword(state.clone()), - parse_absolute_symbol(state.clone()), - parse_relative_symbol(state.clone()), + parse_raw_symbol(state.clone(), create_unknown_packages), + parse_raw_keyword(state.clone(), create_unknown_packages), + parse_absolute_symbol(state.clone(), create_unknown_packages), + parse_relative_symbol(state.clone(), create_unknown_packages), ))(from)?; Ok((upto, Syntax::Symbol(Pos::from_upto(from, upto), sym))) } @@ -301,6 +333,7 @@ pub fn parse_char() -> impl Fn(Span<'_>) -> ParseResult<'_, F, Syn pub fn parse_list( state: Rc>, meta: bool, + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, Syntax> { move |from: Span<'_>| { let (i, _) = tag("(")(from)?; @@ -311,22 +344,34 @@ pub fn parse_list( .borrow_mut() .set_current_package(meta_package_symbol().into()) .expect("meta package is available"); - let (i, h) = preceded(parse_space, parse_symbol(state.clone()))(i)?; + let (i, h) = preceded( + parse_space, + parse_symbol(state.clone(), create_unknown_packages), + )(i)?; // then recover the previous package state .borrow_mut() .set_current_package(saved_package) .expect("previous package is available"); - let (i, t) = many0(preceded(parse_space, parse_syntax(state.clone(), false)))(i)?; + let (i, t) = many0(preceded( + parse_space, + parse_syntax(state.clone(), false, create_unknown_packages), + ))(i)?; let mut xs = vec![h]; xs.extend(t); (i, xs) } else { - many0(preceded(parse_space, parse_syntax(state.clone(), false)))(i)? + many0(preceded( + parse_space, + parse_syntax(state.clone(), false, create_unknown_packages), + ))(i)? }; let (i, end) = opt(preceded( preceded(parse_space, tag(".")), - preceded(parse_space, parse_syntax(state.clone(), false)), + preceded( + parse_space, + parse_syntax(state.clone(), false, create_unknown_packages), + ), ))(i)?; let (i, _) = parse_space(i)?; let (upto, _) = tag(")")(i)?; @@ -341,6 +386,7 @@ pub fn parse_list( pub fn parse_quote( state: Rc>, + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, Syntax> { move |from: Span<'_>| { let (i, c) = opt(parse_char())(from)?; @@ -348,7 +394,7 @@ pub fn parse_quote( Ok((i, c)) } else { let (i, _) = tag("'")(from)?; - let (upto, s) = parse_syntax(state.clone(), false)(i)?; + let (upto, s) = parse_syntax(state.clone(), false, create_unknown_packages)(i)?; let pos = Pos::from_upto(from, upto); Ok((upto, Syntax::Quote(pos, Box::new(s)))) } @@ -359,15 +405,20 @@ pub fn parse_quote( pub fn parse_syntax( state: Rc>, meta: bool, + // this parameter triggers a less strict mode for testing purposes + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, Syntax> { move |from: Span<'_>| { alt(( - context("list", parse_list(state.clone(), meta)), + context( + "list", + parse_list(state.clone(), meta, create_unknown_packages), + ), parse_uint(), parse_num(), - context("path", parse_symbol(state.clone())), + context("path", parse_symbol(state.clone(), create_unknown_packages)), parse_string(), - context("quote", parse_quote(state.clone())), + context("quote", parse_quote(state.clone(), create_unknown_packages)), parse_hash_char(), ))(from) } @@ -375,6 +426,7 @@ pub fn parse_syntax( pub fn parse_maybe_meta( state: Rc>, + create_unknown_packages: bool, ) -> impl Fn(Span<'_>) -> ParseResult<'_, F, Option<(bool, Syntax)>> { move |from: Span<'_>| { let (_, is_eof) = opt(nom::combinator::eof)(from)?; @@ -383,7 +435,7 @@ pub fn parse_maybe_meta( } let (next, meta) = opt(char('!'))(from)?; let meta = meta.is_some(); - let (end, syntax) = parse_syntax(state.clone(), meta)(next)?; + let (end, syntax) = parse_syntax(state.clone(), meta, create_unknown_packages)(next)?; Ok((end, Some((meta, syntax)))) } } @@ -396,8 +448,6 @@ pub mod tests { use proptest::prelude::*; use super::*; - use crate::Symbol; - #[allow(unused_imports)] use crate::{char, keyword, list, num, str, symbol, uint}; fn test<'a, P, R>(mut p: P, i: &'a str, expected: Option) -> bool @@ -439,437 +489,555 @@ pub mod tests { assert!(test(parse_string(), "\"foo\\ \"", Some(str!("foo")))); } - // #[test] - // fn unit_parse_symbol() { - // assert!(test(parse_raw_symbol(), "", None)); - // assert!(test(parse_absolute_symbol(), "", None)); - // assert!(test(parse_relative_symbol(Symbol::root(true)), "", None)); - // assert!(test(parse_relative_symbol(Symbol::root(false)), "", None)); - // assert!(test(parse_symbol(), "", None)); - // assert!(test(parse_symbol(), "~()", Some(symbol!([])))); - // assert!(test(parse_symbol(), ".", None)); - // assert!(test(parse_symbol(), "..", Some(symbol!([""])))); - // assert!(test(parse_symbol(), "foo", Some(symbol!(["foo"])))); - // assert!(test(parse_symbol(), "|foo|", Some(symbol!(["foo"])))); - // assert!(test( - // parse_symbol(), - // "|Hi, bye|", - // Some(symbol!(["Hi, bye"])) - // )); - // assert!(test( - // parse_symbol(), - // "|foo|.|bar|", - // Some(symbol!(["foo", "bar"])) - // )); - // assert!(test( - // parse_symbol(), - // ".|foo|.|bar|", - // Some(symbol!(["foo", "bar"])) - // )); - // assert!(test(parse_symbol(), ".foo", Some(symbol!(["foo"])))); - // assert!(test(parse_symbol(), "..foo", Some(symbol!(["", "foo"])))); - // assert!(test(parse_symbol(), "foo.", Some(symbol!(["foo"])))); - // assert!(test(parse_symbol(), "foo..", Some(symbol!(["foo", ""])))); - // assert!(test(parse_symbol(), ".foo..", Some(symbol!(["foo", ""])))); - // assert!(test(parse_symbol(), ".foo..", Some(symbol!(["foo", ""])))); - // assert!(test( - // parse_symbol(), - // ".foo.bar", - // Some(symbol!(["foo", "bar"])) - // )); - // assert!(test( - // parse_symbol(), - // ".foo?.bar?", - // Some(symbol!(["foo?", "bar?"])) - // )); - // assert!(test( - // parse_symbol(), - // ".fooλ.barλ", - // Some(symbol!(["fooλ", "barλ"])) - // )); - // assert!(test( - // parse_symbol(), - // ".foo\\n.bar\\n", - // Some(symbol!(["foo\n", "bar\n"])) - // )); - // assert!(test( - // parse_symbol(), - // ".foo\\u{00}.bar\\u{00}", - // Some(symbol!(["foo\u{00}", "bar\u{00}"])) - // )); - // assert!(test( - // parse_symbol(), - // ".foo\\.bar", - // Some(symbol!(["foo.bar"])) - // )); - // assert!(test(parse_symbol(), "~(asdf )", Some(symbol!(["asdf"])))); - // assert!(test(parse_symbol(), "~( asdf )", Some(symbol!(["asdf"])))); - // assert!(test(parse_symbol(), "~( asdf)", Some(symbol!(["asdf"])))); - // assert!(test( - // parse_symbol(), - // "~(asdf.fdsa)", - // Some(symbol!(["asdf.fdsa"])) - // )); - // assert!(test( - // parse_symbol(), - // "~(asdf.fdsa arst)", - // Some(symbol!(["arst", "asdf.fdsa"])) - // )); - // assert!(test( - // parse_symbol(), - // "~(asdf.fdsa arst |wfp qwf|)", - // Some(symbol!(["wfp qwf", "arst", "asdf.fdsa"])) - // )); - // } - - // #[test] - // fn unit_parse_keyword() { - // assert!(test(parse_symbol(), "", None)); - // assert!(test(parse_symbol(), ":", None)); - // assert!(test(parse_symbol(), "~:()", Some(keyword!([])))); - // assert!(test(parse_symbol(), ":.", Some(keyword!([""])))); - // assert!(test(parse_symbol(), ":foo", Some(keyword!(["foo"])))); - // assert!(test(parse_symbol(), ":foo.", Some(keyword!(["foo"])))); - // assert!(test(parse_symbol(), ":foo..", Some(keyword!(["foo", ""])))); - // assert!(test( - // parse_symbol(), - // ":foo.bar", - // Some(keyword!(["foo", "bar"])) - // )); - // assert!(test( - // parse_symbol(), - // ":foo?.bar?", - // Some(keyword!(["foo?", "bar?"])) - // )); - // assert!(test( - // parse_symbol(), - // ":fooλ.barλ", - // Some(keyword!(["fooλ", "barλ"])) - // )); - // assert!(test( - // parse_symbol(), - // ":foo\\n.bar\\n", - // Some(keyword!(["foo\n", "bar\n"])) - // )); - // assert!(test( - // parse_symbol(), - // ":foo\\u{00}.bar\\u{00}", - // Some(keyword!(["foo\u{00}", "bar\u{00}"])) - // )); - // assert!(test( - // parse_symbol(), - // ":foo\\.bar", - // Some(keyword!(["foo.bar"])) - // )); - // assert!(test( - // parse_symbol(), - // "~:(x y z)", - // Some(keyword!(["z", "y", "x"])) - // )); - // } - - // #[test] - // fn unit_parse_list() { - // assert!(test(parse_list(), "()", Some(list!([])))); - // assert!(test(parse_list(), "(1 2)", Some(list!([num!(1), num!(2)])),)); - // assert!(test(parse_list(), "(1)", Some(list!([num!(1)])),)); - // assert!(test(parse_list(), "(a)", Some(list!([symbol!(["a"])])),)); - // assert!(test( - // parse_list(), - // "(a b)", - // Some(list!([symbol!(["a"]), symbol!(["b"])])), - // )); - // assert!(test( - // parse_syntax(), - // "(.a .b)", - // Some(list!([symbol!(["a"]), symbol!(["b"])])), - // )); - // assert!(test( - // parse_syntax(), - // "(.foo.bar .foo.bar)", - // Some(list!([symbol!(["foo", "bar"]), symbol!(["foo", "bar"])])), - // )); - // assert!(test( - // parse_syntax(), - // "(a . b)", - // Some(list!([symbol!(["a"])], symbol!(["b"]))), - // )); - // assert!(test( - // parse_syntax(), - // "(.a . .b)", - // Some(list!([symbol!(["a"])], symbol!(["b"]))), - // )); - // assert!(test( - // parse_syntax(), - // "(a b . c)", - // Some(list!([symbol!(["a"]), symbol!(["b"])], symbol!(["c"]))), - // )); - // assert!(test( - // parse_syntax(), - // "(a . (b . c))", - // Some(list!( - // [symbol!(["a"])], - // list!([symbol!(["b"])], symbol!(["c"])) - // )) - // )); - // assert!(test( - // parse_syntax(), - // "(a b c)", - // Some(list!([symbol!(["a"]), symbol!(["b"]), symbol!(["c"])])), - // )); - // assert!(test( - // parse_syntax(), - // "('a' 'b' 'c')", - // Some(list!([char!('a'), char!('b'), char!('c')])), - // )); - - // assert!(test( - // parse_syntax(), - // "(a. b. c.)", - // Some(list!([symbol!(["a"]), symbol!(["b"]), symbol!(["c"])])), - // )); - // assert!(test( - // parse_syntax(), - // "(a.. b.. c..)", - // Some(list!([ - // symbol!(["a", ""]), - // symbol!(["b", ""]), - // symbol!(["c", ""]) - // ])), - // )); - // } - - // #[test] - // fn unit_parse_char() { - // assert!(test(parse_char(), "'a'", Some(char!('a')))); - // assert!(test(parse_char(), "'b'", Some(char!('b')))); - // assert!(test(parse_char(), "'\\u{8f}'", Some(char!('\u{8f}')))); - // assert!(test(parse_char(), "'\\t'", Some(char!('\t')))); - // assert!(test(parse_char(), "'('", None)); - // assert!(test(parse_char(), "'\\('", Some(char!('(')))); - // } - // #[test] - // fn unit_parse_hash_char() { - // assert!(test(parse_hash_char(), "#\\a", Some(char!('a')))); - // assert!(test(parse_hash_char(), "#\\b", Some(char!('b')))); - // assert!(test(parse_hash_char(), r"#\b", Some(char!('b')))); - // assert!(test(parse_hash_char(), "#\\u{8f}", Some(char!('\u{8f}')))); - // assert!(test(parse_syntax(), "#\\a", Some(char!('a')))); - // assert!(test(parse_syntax(), "#\\b", Some(char!('b')))); - // assert!(test(parse_syntax(), r"#\b", Some(char!('b')))); - // assert!(test(parse_syntax(), r"#\u{8f}", Some(char!('\u{8f}')))); - // } - - // #[test] - // fn unit_parse_quote() { - // assert!(test( - // parse_quote(), - // "'.a", - // Some(Syntax::Quote(Pos::No, Box::new(symbol!(["a"])))) - // )); - // assert!(test( - // parse_syntax(), - // "':a", - // Some(Syntax::Quote(Pos::No, Box::new(keyword!(["a"])))) - // )); - // assert!(test( - // parse_syntax(), - // "'a", - // Some(Syntax::Quote(Pos::No, Box::new(symbol!(["a"])))) - // )); - // assert!(test(parse_quote(), "'a'", Some(char!('a')))); - // assert!(test(parse_quote(), "'a'", Some(char!('a')))); - // assert!(test( - // parse_syntax(), - // "'(a b)", - // Some(Syntax::Quote( - // Pos::No, - // Box::new(list!([symbol!(["a"]), symbol!(["b"])])) - // )) - // )); - // assert!(test( - // parse_syntax(), - // "('a)", - // Some(list!([Syntax::Quote(Pos::No, Box::new(symbol!(['a'])))])) - // )); - - // assert!(test( - // parse_syntax(), - // "('a' 'b' 'c')", - // Some(list!([char!('a'), char!('b'), char!('c')])), - // )); - // } - - // #[test] - // fn unit_parse_num() { - // assert!(test(parse_num(), "0", Some(num!(0)))); - // assert!(test(parse_num(), "00", Some(num!(0)))); - // assert!(test(parse_num(), "001", Some(num!(1)))); - // assert!(test(parse_num(), "0b0", Some(num!(0)))); - // assert!(test(parse_num(), "0o0", Some(num!(0)))); - // assert!(test(parse_num(), "0d0", Some(num!(0)))); - // assert!(test(parse_num(), "0x0", Some(num!(0)))); - // assert!(test(parse_num(), "0xf", Some(num!(15)))); - // assert!(test(parse_num(), "0x0f", Some(num!(15)))); - // assert!(test( - // parse_num(), - // "0xffff_ffff_ffff_ffff", - // Some(num!(0xffff_ffff_ffff_ffff)) - // )); - // assert!(test( - // parse_num(), - // "0x1234_5678_9abc_def0", - // Some(num!(0x1234_5678_9abc_def0)) - // )); - // assert!(test( - // parse_num(), - // &format!("0x{}", Scalar::most_positive().hex_digits()), - // Some(num!(Num::Scalar(Scalar::most_positive()))) - // )); - // assert!(test( - // parse_num(), - // "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000", - // Some(Syntax::Num( - // Pos::No, - // Num::Scalar(::ZERO - Scalar::from(1u64)) - // )), - // )); - // assert!(test( - // parse_num(), - // "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", - // None, - // )); - // assert!(test(parse_num(), "-0", Some(num!(0)))); - // let mut tmp = Num::U64(1u64); - // tmp /= Num::U64(2u64); - // assert!(test(parse_num(), "1/2", Some(Syntax::Num(Pos::No, tmp)))); - // let mut tmp = Num::U64(0u64); - // tmp -= Num::U64(1u64); - // tmp /= Num::U64(2u64); - // assert!(test(parse_num(), "-1/2", Some(Syntax::Num(Pos::No, tmp)))); - // } - - // #[test] - // fn unit_parse_syntax_misc() { - // let vec: Vec = vec![ - // 0x6e, 0x2e, 0x50, 0x55, 0xdc, 0xf6, 0x14, 0x86, 0xb0, 0x3b, 0xb8, 0x0e, 0xd2, 0xb3, - // 0xf1, 0xa3, 0x5c, 0x30, 0xe1, 0x22, 0xde, 0xfe, 0xba, 0xe8, 0x24, 0xfa, 0xe4, 0xed, - // 0x32, 0x40, 0x8e, 0x87, - // ] - // .into_iter() - // .rev() - // .collect(); - // assert!(test( - // parse_syntax(), - // "(0x6e2e5055dcf61486b03bb80ed2b3f1a35c30e122defebae824fae4ed32408e87)", - // Some(list!([num!(Num::Scalar(f_from_le_bytes(&vec)))])), - // )); - - // assert!(test(parse_syntax(), ".\\.", Some(symbol!(["."])))); - // assert!(test(parse_syntax(), ".\\'", Some(symbol!(["'"])))); - // assert!(test( - // parse_syntax(), - // ".\\'\\u{8e}\\u{fffc}\\u{201b}", - // Some(symbol!(["'\u{8e}\u{fffc}\u{201b}"])), - // )); - // assert!(test( - // parse_syntax(), - // "(lambda (🚀) 🚀)", - // Some(list!([ - // symbol!(["lambda"]), - // list!([symbol!(["🚀"])]), - // symbol!(["🚀"]) - // ])), - // )); - // assert!(test( - // parse_syntax(), - // "11242421860377074631u64", - // Some(uint!(11242421860377074631)) - // )); - - // assert!(test( - // parse_syntax(), - // ":\u{ae}\u{60500}\u{87}..)", - // Some(keyword!(["®\u{60500}\u{87}", ""])) - // )); - // assert!(test( - // parse_syntax(), - // "(~:() 11242421860377074631u64 . :\u{ae}\u{60500}\u{87}..)", - // Some(list!( - // [keyword!([]), uint!(11242421860377074631)], - // keyword!(["®\u{60500}\u{87}", ""]) - // )) - // )); - // assert!(test( - // parse_syntax(), - // "((\"\"))", - // Some(list!([list!([Syntax::String(Pos::No, "".to_string())])])) - // )); - - // assert!(test( - // parse_syntax(), - // "((=))", - // Some(list!([list!([symbol!(["="])])])) - // )); - // assert!(test( - // parse_syntax(), - // "('.. . a)", - // Some(list!( - // [Syntax::Quote(Pos::No, Box::new(symbol!([""])))], - // symbol!(["a"]) - // )) - // )); - // assert_eq!( - // "(.. . a)", - // format!("{}", list!(Scalar, [symbol!([""])], symbol!(["a"]))) - // ); - // assert_eq!( - // "('.. . a)", - // format!( - // "{}", - // list!( - // Scalar, - // [Syntax::Quote(Pos::No, Box::new(symbol!([""])))], - // symbol!(["a"]) - // ) - // ) - // ); - // assert!(test(parse_syntax(), "'\\('", Some(char!('(')))); - // assert_eq!("'\\('", format!("{}", char!(Scalar, '('))); - // assert_eq!( - // "(' ' . a)", - // format!("{}", list!(Scalar, [char!(' ')], symbol!(["a"]))) - // ); - // assert!(test( - // parse_syntax(), - // "(' ' . a)", - // Some(list!([char!(' ')], symbol!(["a"]))) - // )); - // assert!(test(parse_syntax(), "(cons # \"\")", None)); - // assert!(test(parse_syntax(), "#", None)); - // } - - // #[test] - // fn test_minus_zero_symbol() { - // let x: Syntax = symbol!(["-0"]); - // let text = format!("{}", x); - // let (_, res) = parse_syntax()(Span::new(&text)).expect("valid parse"); - // // eprintln!("------------------"); - // // eprintln!("{}", text); - // // eprintln!("{} {:?}", x, x); - // // eprintln!("{} {:?}", res, res); - // assert_eq!(x, res) - // } - - // proptest! { - // #[test] - // fn prop_syntax(x in any::>()) { - // let text = format!("{}", x); - // let (_, res) = parse_syntax()(Span::new(&text)).expect("valid parse"); - // // eprintln!("------------------"); - // // eprintln!("x {} {:?}", x, x); - // // eprintln!("res {} {:?}", res, res); - // assert_eq!(x, res) - // } - // } + #[test] + fn unit_parse_symbol() { + let state_ = State::minimal().mutable(); + let state = || state_.clone(); + assert!(test(parse_raw_symbol(state(), true), "", None)); + assert!(test(parse_absolute_symbol(state(), true), "", None)); + assert!(test(parse_relative_symbol(state(), true), "", None)); + assert!(test(parse_relative_symbol(state(), true), "", None)); + assert!(test(parse_symbol(state(), true), "", None)); + assert!(test(parse_symbol(state(), true), "~()", Some(symbol!([])))); + assert!(test(parse_symbol(state(), true), ".", None)); + assert!(test(parse_symbol(state(), true), "..", Some(symbol!([""])))); + assert!(test( + parse_symbol(state(), true), + "foo", + Some(symbol!(["foo"])) + )); + assert!(test( + parse_symbol(state(), true), + "|foo|", + Some(symbol!(["foo"])) + )); + assert!(test( + parse_symbol(state(), true), + "|Hi, bye|", + Some(symbol!(["Hi, bye"])) + )); + assert!(test( + parse_symbol(state(), true), + "|foo|.|bar|", + Some(symbol!(["foo", "bar"])) + )); + assert!(test( + parse_symbol(state(), true), + ".|foo|.|bar|", + Some(symbol!(["foo", "bar"])) + )); + assert!(test( + parse_symbol(state(), true), + ".foo", + Some(symbol!(["foo"])) + )); + assert!(test( + parse_symbol(state(), true), + "..foo", + Some(symbol!(["", "foo"])) + )); + assert!(test( + parse_symbol(state(), true), + "foo.", + Some(symbol!(["foo"])) + )); + assert!(test( + parse_symbol(state(), true), + "foo..", + Some(symbol!(["foo", ""])) + )); + assert!(test( + parse_symbol(state(), true), + ".foo..", + Some(symbol!(["foo", ""])) + )); + assert!(test( + parse_symbol(state(), true), + ".foo..", + Some(symbol!(["foo", ""])) + )); + assert!(test( + parse_symbol(state(), true), + ".foo.bar", + Some(symbol!(["foo", "bar"])) + )); + assert!(test( + parse_symbol(state(), true), + ".foo?.bar?", + Some(symbol!(["foo?", "bar?"])) + )); + assert!(test( + parse_symbol(state(), true), + ".fooλ.barλ", + Some(symbol!(["fooλ", "barλ"])) + )); + assert!(test( + parse_symbol(state(), true), + ".foo\\n.bar\\n", + Some(symbol!(["foo\n", "bar\n"])) + )); + assert!(test( + parse_symbol(state(), true), + ".foo\\u{00}.bar\\u{00}", + Some(symbol!(["foo\u{00}", "bar\u{00}"])) + )); + assert!(test( + parse_symbol(state(), true), + ".foo\\.bar", + Some(symbol!(["foo.bar"])) + )); + assert!(test( + parse_symbol(state(), true), + "~(asdf )", + Some(symbol!(["asdf"])) + )); + assert!(test( + parse_symbol(state(), true), + "~( asdf )", + Some(symbol!(["asdf"])) + )); + assert!(test( + parse_symbol(state(), true), + "~( asdf)", + Some(symbol!(["asdf"])) + )); + assert!(test( + parse_symbol(state(), true), + "~(asdf.fdsa)", + Some(symbol!(["asdf.fdsa"])) + )); + assert!(test( + parse_symbol(state(), true), + "~(asdf.fdsa arst)", + Some(symbol!(["arst", "asdf.fdsa"])) + )); + assert!(test( + parse_symbol(state(), true), + "~(asdf.fdsa arst |wfp qwf|)", + Some(symbol!(["wfp qwf", "arst", "asdf.fdsa"])) + )); + } + + #[test] + fn unit_parse_keyword() { + let state_ = State::minimal().mutable(); + let state = || state_.clone(); + assert!(test(parse_symbol(state(), true), "", None)); + assert!(test(parse_symbol(state(), true), ":", None)); + assert!(test( + parse_symbol(state(), true), + "~:()", + Some(keyword!([])) + )); + assert!(test( + parse_symbol(state(), true), + ":.", + Some(keyword!([""])) + )); + assert!(test( + parse_symbol(state(), true), + ":foo", + Some(keyword!(["foo"])) + )); + assert!(test( + parse_symbol(state(), true), + ":foo.", + Some(keyword!(["foo"])) + )); + assert!(test( + parse_symbol(state(), true), + ":foo..", + Some(keyword!(["foo", ""])) + )); + assert!(test( + parse_symbol(state(), true), + ":foo.bar", + Some(keyword!(["foo", "bar"])) + )); + assert!(test( + parse_symbol(state(), true), + ":foo?.bar?", + Some(keyword!(["foo?", "bar?"])) + )); + assert!(test( + parse_symbol(state(), true), + ":fooλ.barλ", + Some(keyword!(["fooλ", "barλ"])) + )); + assert!(test( + parse_symbol(state(), true), + ":foo\\n.bar\\n", + Some(keyword!(["foo\n", "bar\n"])) + )); + assert!(test( + parse_symbol(state(), true), + ":foo\\u{00}.bar\\u{00}", + Some(keyword!(["foo\u{00}", "bar\u{00}"])) + )); + assert!(test( + parse_symbol(state(), true), + ":foo\\.bar", + Some(keyword!(["foo.bar"])) + )); + assert!(test( + parse_symbol(state(), true), + "~:(x y z)", + Some(keyword!(["z", "y", "x"])) + )); + } + + #[test] + fn unit_parse_list() { + let state_ = State::minimal().mutable(); + let state = || state_.clone(); + assert!(test( + parse_list(state(), false, true), + "()", + Some(list!([])) + )); + assert!(test( + parse_list(state(), false, true), + "(1 2)", + Some(list!([num!(1), num!(2)])), + )); + assert!(test( + parse_list(state(), false, true), + "(1)", + Some(list!([num!(1)])), + )); + assert!(test( + parse_list(state(), false, true), + "(a)", + Some(list!([symbol!(["a"])])), + )); + assert!(test( + parse_list(state(), false, true), + "(a b)", + Some(list!([symbol!(["a"]), symbol!(["b"])])), + )); + assert!(test( + parse_syntax(state(), false, true), + "(.a .b)", + Some(list!([symbol!(["a"]), symbol!(["b"])])), + )); + assert!(test( + parse_syntax(state(), false, true), + "(.foo.bar .foo.bar)", + Some(list!([symbol!(["foo", "bar"]), symbol!(["foo", "bar"])])), + )); + assert!(test( + parse_syntax(state(), false, true), + "(a . b)", + Some(list!([symbol!(["a"])], symbol!(["b"]))), + )); + assert!(test( + parse_syntax(state(), false, true), + "(.a . .b)", + Some(list!([symbol!(["a"])], symbol!(["b"]))), + )); + assert!(test( + parse_syntax(state(), false, true), + "(a b . c)", + Some(list!([symbol!(["a"]), symbol!(["b"])], symbol!(["c"]))), + )); + assert!(test( + parse_syntax(state(), false, true), + "(a . (b . c))", + Some(list!( + [symbol!(["a"])], + list!([symbol!(["b"])], symbol!(["c"])) + )) + )); + assert!(test( + parse_syntax(state(), false, true), + "(a b c)", + Some(list!([symbol!(["a"]), symbol!(["b"]), symbol!(["c"])])), + )); + assert!(test( + parse_syntax(state(), false, true), + "('a' 'b' 'c')", + Some(list!([char!('a'), char!('b'), char!('c')])), + )); + assert!(test( + parse_syntax(state(), false, true), + "(a. b. c.)", + Some(list!([symbol!(["a"]), symbol!(["b"]), symbol!(["c"])])), + )); + assert!(test( + parse_syntax(state(), false, true), + "(a.. b.. c..)", + Some(list!([ + symbol!(["a", ""]), + symbol!(["b", ""]), + symbol!(["c", ""]) + ])), + )); + } + + #[test] + fn unit_parse_char() { + assert!(test(parse_char(), "'a'", Some(char!('a')))); + assert!(test(parse_char(), "'b'", Some(char!('b')))); + assert!(test(parse_char(), "'\\u{8f}'", Some(char!('\u{8f}')))); + assert!(test(parse_char(), "'\\t'", Some(char!('\t')))); + assert!(test(parse_char(), "'('", None)); + assert!(test(parse_char(), "'\\('", Some(char!('(')))); + } + + #[test] + fn unit_parse_hash_char() { + let state_ = State::minimal().mutable(); + let state = || state_.clone(); + assert!(test(parse_hash_char(), "#\\a", Some(char!('a')))); + assert!(test(parse_hash_char(), "#\\b", Some(char!('b')))); + assert!(test(parse_hash_char(), r"#\b", Some(char!('b')))); + assert!(test(parse_hash_char(), "#\\u{8f}", Some(char!('\u{8f}')))); + assert!(test( + parse_syntax(state(), false, false), + "#\\a", + Some(char!('a')) + )); + assert!(test( + parse_syntax(state(), false, false), + "#\\b", + Some(char!('b')) + )); + assert!(test( + parse_syntax(state(), false, false), + r"#\b", + Some(char!('b')) + )); + assert!(test( + parse_syntax(state(), false, false), + r"#\u{8f}", + Some(char!('\u{8f}')) + )); + } + + #[test] + fn unit_parse_quote() { + let state_ = State::minimal().mutable(); + let state = || state_.clone(); + assert!(test( + parse_quote(state(), true), + "'.a", + Some(Syntax::Quote(Pos::No, Box::new(symbol!(["a"])))) + )); + assert!(test( + parse_syntax(state(), false, true), + "':a", + Some(Syntax::Quote(Pos::No, Box::new(keyword!(["a"])))) + )); + assert!(test( + parse_syntax(state(), false, true), + "'a", + Some(Syntax::Quote(Pos::No, Box::new(symbol!(["a"])))) + )); + assert!(test(parse_quote(state(), true), "'a'", Some(char!('a')))); + assert!(test(parse_quote(state(), true), "'a'", Some(char!('a')))); + assert!(test( + parse_syntax(state(), false, true), + "'(a b)", + Some(Syntax::Quote( + Pos::No, + Box::new(list!([symbol!(["a"]), symbol!(["b"])])) + )) + )); + assert!(test( + parse_syntax(state(), false, true), + "('a)", + Some(list!([Syntax::Quote(Pos::No, Box::new(symbol!(['a'])))])) + )); + assert!(test( + parse_syntax(state(), false, true), + "('a' 'b' 'c')", + Some(list!([char!('a'), char!('b'), char!('c')])), + )); + } + + #[test] + fn unit_parse_num() { + assert!(test(parse_num(), "0", Some(num!(0)))); + assert!(test(parse_num(), "00", Some(num!(0)))); + assert!(test(parse_num(), "001", Some(num!(1)))); + assert!(test(parse_num(), "0b0", Some(num!(0)))); + assert!(test(parse_num(), "0o0", Some(num!(0)))); + assert!(test(parse_num(), "0d0", Some(num!(0)))); + assert!(test(parse_num(), "0x0", Some(num!(0)))); + assert!(test(parse_num(), "0xf", Some(num!(15)))); + assert!(test(parse_num(), "0x0f", Some(num!(15)))); + assert!(test( + parse_num(), + "0xffff_ffff_ffff_ffff", + Some(num!(0xffff_ffff_ffff_ffff)) + )); + assert!(test( + parse_num(), + "0x1234_5678_9abc_def0", + Some(num!(0x1234_5678_9abc_def0)) + )); + assert!(test( + parse_num(), + &format!("0x{}", Scalar::most_positive().hex_digits()), + Some(num!(Num::Scalar(Scalar::most_positive()))) + )); + assert!(test( + parse_num(), + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000", + Some(Syntax::Num( + Pos::No, + Num::Scalar(::ZERO - Scalar::from(1u64)) + )), + )); + assert!(test( + parse_num(), + "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", + None, + )); + assert!(test(parse_num(), "-0", Some(num!(0)))); + let mut tmp = Num::U64(1u64); + tmp /= Num::U64(2u64); + assert!(test(parse_num(), "1/2", Some(Syntax::Num(Pos::No, tmp)))); + let mut tmp = Num::U64(0u64); + tmp -= Num::U64(1u64); + tmp /= Num::U64(2u64); + assert!(test(parse_num(), "-1/2", Some(Syntax::Num(Pos::No, tmp)))); + } + + #[test] + fn unit_parse_syntax_misc() { + let vec: Vec = vec![ + 0x6e, 0x2e, 0x50, 0x55, 0xdc, 0xf6, 0x14, 0x86, 0xb0, 0x3b, 0xb8, 0x0e, 0xd2, 0xb3, + 0xf1, 0xa3, 0x5c, 0x30, 0xe1, 0x22, 0xde, 0xfe, 0xba, 0xe8, 0x24, 0xfa, 0xe4, 0xed, + 0x32, 0x40, 0x8e, 0x87, + ] + .into_iter() + .rev() + .collect(); + let state_ = State::minimal().mutable(); + let state = || state_.clone(); + + assert!(test( + parse_syntax(state(), false, true), + "(0x6e2e5055dcf61486b03bb80ed2b3f1a35c30e122defebae824fae4ed32408e87)", + Some(list!([num!(Num::Scalar(f_from_le_bytes(&vec)))])), + )); + assert!(test( + parse_syntax(state(), false, true), + ".\\.", + Some(symbol!(["."])) + )); + assert!(test( + parse_syntax(state(), false, true), + ".\\'", + Some(symbol!(["'"])) + )); + assert!(test( + parse_syntax(state(), false, true), + ".\\'\\u{8e}\\u{fffc}\\u{201b}", + Some(symbol!(["'\u{8e}\u{fffc}\u{201b}"])), + )); + assert!(test( + parse_syntax(state(), false, true), + "(lambda (🚀) 🚀)", + Some(list!([ + symbol!(["lambda"]), + list!([symbol!(["🚀"])]), + symbol!(["🚀"]) + ])), + )); + assert!(test( + parse_syntax(state(), false, true), + "11242421860377074631u64", + Some(uint!(11242421860377074631)) + )); + assert!(test( + parse_syntax(state(), false, true), + ":\u{ae}\u{60500}\u{87}..)", + Some(keyword!(["®\u{60500}\u{87}", ""])) + )); + assert!(test( + parse_syntax(state(), false, true), + "(~:() 11242421860377074631u64 . :\u{ae}\u{60500}\u{87}..)", + Some(list!( + [keyword!([]), uint!(11242421860377074631)], + keyword!(["®\u{60500}\u{87}", ""]) + )) + )); + assert!(test( + parse_syntax(state(), false, true), + "((\"\"))", + Some(list!([list!([Syntax::String(Pos::No, "".to_string())])])) + )); + assert!(test( + parse_syntax(state(), false, true), + "((=))", + Some(list!([list!([symbol!(["="])])])) + )); + assert!(test( + parse_syntax(state(), false, true), + "('.. . a)", + Some(list!( + [Syntax::Quote(Pos::No, Box::new(symbol!([""])))], + symbol!(["a"]) + )) + )); + assert_eq!( + "(.. . .a)", + format!("{}", list!(Scalar, [symbol!([""])], symbol!(["a"]))) + ); + assert_eq!( + "('.. . .a)", + format!( + "{}", + list!( + Scalar, + [Syntax::Quote(Pos::No, Box::new(symbol!([""])))], + symbol!(["a"]) + ) + ) + ); + assert!(test( + parse_syntax(state(), false, true), + "'\\('", + Some(char!('(')) + )); + assert_eq!("'\\('", format!("{}", char!(Scalar, '('))); + assert_eq!( + "(' ' . .a)", + format!("{}", list!(Scalar, [char!(' ')], symbol!(["a"]))) + ); + assert!(test( + parse_syntax(state(), false, true), + "(' ' . a)", + Some(list!([char!(' ')], symbol!(["a"]))) + )); + assert!(test( + parse_syntax(state(), false, true), + "(cons # \"\")", + None + )); + assert!(test(parse_syntax(state(), false, true), "#", None)); + } + + #[test] + fn test_minus_zero_symbol() { + let x: Syntax = symbol!(["-0"]); + let text = format!("{}", x); + let (_, res) = parse_syntax(State::minimal().mutable(), false, true)(Span::new(&text)) + .expect("valid parse"); + assert_eq!(x, res) + } + + proptest! { + #[test] + fn prop_syntax(x in any::>()) { + let text = format!("{}", x); + let (_, res) = parse_syntax(State::minimal().mutable(), false, true)(Span::new(&text)).expect("valid parse"); + // eprintln!("------------------"); + // eprintln!("x {} {:?}", x, x); + // eprintln!("res {} {:?}", res, res); + assert_eq!(x, res) + } + } } diff --git a/src/state.rs b/src/state.rs index 86f2c6af9b..3d0787c662 100644 --- a/src/state.rs +++ b/src/state.rs @@ -78,22 +78,45 @@ impl State { self.get_current_package().fmt_to_string(symbol) } - pub fn intern_fold>(&mut self, init: SymbolRef, path: &[A]) -> Result { + fn intern_fold>( + &mut self, + init: SymbolRef, + path: &[A], + create_unknown_packges: bool, + ) -> Result { path.iter() .try_fold(init, |acc, s| match self.symbol_packages.get_mut(&acc) { Some(package) => Ok(package.intern(String::from(s.as_ref()))), - None => bail!("Package {acc} not found"), + None => { + if create_unknown_packges { + let mut package = Package::new(acc); + let symbol = package.intern(String::from(s.as_ref())); + self.add_package(package); + Ok(symbol) + } else { + bail!("Package {acc} not found") + } + } }) } #[inline] - pub fn intern_path>(&mut self, path: &[A], keyword: bool) -> Result { - self.intern_fold(Symbol::root(keyword).into(), path) + pub fn intern_path>( + &mut self, + path: &[A], + keyword: bool, + create_unknown_packges: bool, + ) -> Result { + self.intern_fold(Symbol::root(keyword).into(), path, create_unknown_packges) } #[inline] - pub fn intern_relative_path>(&mut self, path: &[A]) -> Result { - self.intern_fold(self.current_package.clone(), path) + pub fn intern_relative_path>( + &mut self, + path: &[A], + create_unknown_packges: bool, + ) -> Result { + self.intern_fold(self.current_package.clone(), path, create_unknown_packges) } #[inline] @@ -262,7 +285,7 @@ pub mod test { test_printing_helper(&state, user_sym, ".lurk.user.user-sym"); let path = ["my-package", "my-other-symbol"]; - state.intern_path(&path, false).unwrap(); + state.intern_path(&path, false, false).unwrap(); test_printing_helper( &state, SymbolRef::new(Symbol::sym(&path)),