add more parser tests

This commit is contained in:
mehbark 2026-01-02 23:56:42 -05:00
parent 6f71d9f5b3
commit 79c3113689
5 changed files with 145 additions and 27 deletions

17
Cargo.lock generated
View file

@ -99,6 +99,12 @@ dependencies = [
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@ -206,6 +212,16 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "pretty_assertions"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
dependencies = [
"diff",
"yansi",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.104" version = "1.0.104"
@ -232,6 +248,7 @@ dependencies = [
"ariadne", "ariadne",
"chumsky", "chumsky",
"logos", "logos",
"pretty_assertions",
] ]
[[package]] [[package]]

View file

@ -7,3 +7,6 @@ edition = "2024"
ariadne = { version = "0.6.0", features = ["auto-color"]} ariadne = { version = "0.6.0", features = ["auto-color"]}
chumsky = { version = "0.12.0", features = ["pratt"] } chumsky = { version = "0.12.0", features = ["pratt"] }
logos = "0.16.0" logos = "0.16.0"
[dev-dependencies]
pretty_assertions = "1.4.1"

View file

@ -14,7 +14,7 @@ Values:
`double x = x * 2` `double x = x * 2`
```rust ```rust
double = fn([x] [x]) ( double = fn([x] [x]) (
^x = x * 2; ^x := x * 2;
); );
``` ```
@ -22,7 +22,7 @@ double = fn([x] [x]) (
```rust ```rust
;; same as apply = fn([f x] [x]) ( ... ) ;; same as apply = fn([f x] [x]) ( ... )
fn apply([f x] [x]) ( fn apply([f x] [x]) (
^x = f x; ^x := f x;
); );
;; f would have to be like fn([a] [a]) ( ... ) ;; f would have to be like fn([a] [a]) ( ... )
@ -37,10 +37,10 @@ fn apply([f x] [x]) (
``` ```
```rust ```rust
fn make_counter([] [inc]) ( fn make_counter([] [inc]) (
i = 0; i := 0;
^inc = fn([] [i]) ( ^inc := fn([] [i]) (
i = i + 1; i := i + 1;
^i = i; ^i := i;
); );
;; or fn ^inc(...) ;; or fn ^inc(...)
@ -51,20 +51,20 @@ fn make_counter([] [inc]) (
```rust ```rust
;; omitting the return means it's the same ;; omitting the return means it's the same
fn desat([h s l a]) ( fn desat([h s l a]) (
^s = ^s / 2; ^s := ^s / 2;
) )
``` ```
`compose f g x = f (g x)` `compose f g x = f (g x)`
```rust ```rust
fn compose([f g x] [x]) ( fn compose([f g x] [x]) (
^x = g x; ^x := g x;
^x = f x; ^x := f x;
) )
f = fn([x]) (^x = x + 2;); f := fn([x]) (^x := x + 2;);
g = fn([x]) (^x = x * 3;); g := fn([x]) (^x := x * 3;);
f2 = f; f2 := f;
compose f g x == (((compose f) g) x) == compose {f: f2, g} x == compose {x} f g compose f g x == (((compose f) g) x) == compose {f: f2, g} x == compose {x} f g
``` ```

View file

@ -85,6 +85,9 @@ impl fmt::Display for Ast {
body, body,
} => { } => {
let body: Vec<_> = body.iter().map(|stmt| format!("{stmt}")).collect(); let body: Vec<_> = body.iter().map(|stmt| format!("{stmt}")).collect();
if body.is_empty() {
write!(f, "(fn ([{}] [{}]))", inputs.join(" "), outputs.join(" "),)
} else {
write!( write!(
f, f,
"(fn ([{}] [{}]) {})", "(fn ([{}] [{}]) {})",
@ -93,6 +96,7 @@ impl fmt::Display for Ast {
body.join(" ") body.join(" ")
) )
} }
}
Ast::Map(body) => { Ast::Map(body) => {
let body: Vec<_> = body.iter().map(|stmt| format!("{stmt}")).collect(); let body: Vec<_> = body.iter().map(|stmt| format!("{stmt}")).collect();
write!(f, "{{{}}}", body.join(" ")) write!(f, "{{{}}}", body.join(" "))

View file

@ -1,7 +1,7 @@
use crate::parser::*; use crate::parser::*;
fn test(src: &str, expected: &str) { fn test(src: &str, expected: &str) {
assert_eq!( pretty_assertions::assert_eq!(
parse(src) parse(src)
.into_iter() .into_iter()
.map(|stmt| format!("{stmt}")) .map(|stmt| format!("{stmt}"))
@ -16,10 +16,27 @@ fn double() {
test( test(
" "
fn double([x]) ( fn double([x]) (
^x = x * 2; ^x := x * 2;
) )
", ",
"(set! double (fn ([x] [x]) (^x = (x * 2))))", "
(set! double (fn ([x] [x]) (set! ^x (x * 2))))
",
);
}
#[test]
fn apply() {
test(
"
# same as apply = fn([f x] [x]) ( ... )
fn apply([f x] [x]) (
^x := f x;
)
# f would have to be like fn([a] [a]) ( ... )
",
"(set! apply (fn ([f x] [x]) (set! ^x (f x))))",
); );
} }
@ -28,15 +45,92 @@ fn make_counter() {
test( test(
" "
fn make_counter([] [inc]) ( fn make_counter([] [inc]) (
i = 0; i := 0;
^inc = fn([] [i]) ( ^inc := fn([] [i]) (
i = i + 1; i := i + 1;
^i = i; ^i := i;
); );
# or fn ^inc(...) # or fn ^inc(...)
) )
", ",
"(set! make_counter (fn ([] [inc]) (i = 0) (^inc = (fn ([] [i]) (i = (i + 1)) (^i = i)))))", "
(set! make_counter \
(fn ([] [inc]) \
(set! i 0) \
(set! ^inc (fn ([] [i]) \
(set! i (i + 1)) \
(set! ^i i)))))
",
);
}
#[test]
fn desat() {
test(
"
fn desat([h s l a]) (
^s := ^s / 2;
)
",
"(set! desat (fn ([h s l a] [h s l a]) (set! ^s (^s / 2))))",
);
}
#[test]
fn compose() {
test(
"
fn compose([f g x] [x]) (
^x := g x;
^x := f x;
);
f := fn([x]) (^x := x + 2;);
g := fn([x]) (^x := x * 3;);
f2 := f;
compose f g x = (((compose f) g) x);
compose f g x = compose {^f := f2; ^g} x;
compose f g x = compose {^x} f g;
",
"
(set! compose (fn ([f g x] [x]) (set! ^x (g x)) (set! ^x (f x))));
(set! f (fn ([x] [x]) (set! ^x (x + 2))));
(set! g (fn ([x] [x]) (set! ^x (x * 3))));
(set! f2 f);
((((compose f) g) x) = ((((((compose f)) g)) x)));
((((compose f) g) x) = ((compose {(set! ^f f2) ^g}) x));
((((compose f) g) x) = (((compose {^x}) f) g))
",
);
}
#[test]
fn id() {
test("fn id([x]) ()", "(set! id (fn ([x] [x])))");
}
#[test]
fn map() {
test(
"
foo := 3;
{
x := 42;
^twice_x := x * 2;
^thrice_x := x * 3;
^foo;
}
",
"
(set! foo 3);
{\
(set! x 42) \
(set! ^twice_x (x * 2)) \
(set! ^thrice_x (x * 3)) \
^foo\
}
",
); );
} }