Skip to content

Commit

Permalink
vine: add lambda calculus test (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjjfvi authored Jan 16, 2025
1 parent ffd6272 commit 08cfedd
Show file tree
Hide file tree
Showing 67 changed files with 1,092 additions and 205 deletions.
3 changes: 2 additions & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"strs",
"unpark",
"vecs",
"visitee"
"visitee",
"whnf"
],
"dictionaries": [
"rust"
Expand Down
172 changes: 172 additions & 0 deletions tests/programs/lambda.vi
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@

use std::data::Map;

pub fn main(&io: &IO) {
while io.prompt("> ") is Some(line) {
match Term::parse(~_, line) {
Ok(term) { io.println(term.print_normal(0)) }
Err(err) { io.println("error: " ++ err) }
}
}
}

pub enum Term {
Lambda(List[~Term], Term),
Apply(Term, Term),
Spine(String, List[Term]),
}

pub mod Term {
fn whnf(term: Term) -> Term {
match term {
Term::Apply(fun, arg) {
fun = fun.whnf();
match fun {
Term::Lambda(param, body) {
bind(param, arg);
body.whnf()
}
Term::Spine(var, args) { Term::Spine(var, args ++ [arg]) }
}
}
term { term }
}
}

pub fn print_normal(term: Term, depth: N32) -> String {
match term.whnf() {
Term::Lambda(param, body) {
let var = new_var(depth);
bind(param, Term::Spine(var, []));
"\\" ++ var ++ ". " ++ body.print_normal(depth + 1)
}
Term::Spine(var, args) {
if args.len() == 0 {
var
} else {
let out = "(" ++ var;
let iter = args.into_iter();
while iter.next() is Some(arg) {
out ++= " " ++ arg.print_normal(depth);
}
out ++ ")"
}
}
}
}

fn bind(uses: List[~Term], term: Term) {
let iter = uses.into_iter();
while iter.next() is Some(out) {
~out = term;
}
}

pub fn parse(io: IO, source: String) -> Result[Term, String] {
let err;
let parser = Parser({ io, scope: Map::new(String::cmp), chars: source.chars, error: move ~err });
let term = parser.parse_term();
~parser.error = None;
if err is Some(error) {
Err(error)
} else {
Ok(term)
}
}
}

struct Parser {
io: IO,
scope: Map[String, List[List[~Term]]],
chars: List[Char],
error: ~Option[String],
}

mod Parser {
pub fn parse_term(&self: &Parser) -> Term {
let term = self.parse_atom();
self.skip_ws();
while self.chars.len() != 0 && self.chars.get(0).* != ')' {
term = Term::Apply(term, self.parse_atom());
self.skip_ws();
}
term
}

fn parse_atom(&self: &Parser) -> Term {
self.skip_ws();
if self.chars.len() == 0 {
self.error("expected term");
}
let char = self.chars.get(0).*;
self.io.println(String({ chars: [char] }));
if char == '\\' {
self.io.println("lambda");
self.chars.pop_front();
self.skip_ws();
let var = self.parse_var();
self.io.println(var);
self.expect_char('.');
self.scope.get_or_insert(var, []).*.push_front([]);
let body = self.parse_atom();
let uses = self.scope.get(&var).unwrap().*.pop_front().unwrap();
Term::Lambda(uses, body)
} else if char == '(' {
self.chars.pop_front();
let term = self.parse_term();
self.expect_char(')');
term
} else {
let var = self.parse_var();
if self.scope.get(&var) is Some(&binds) && binds.len() != 0 {
let term;
binds.get(0).*.push_back(move ~term);
term
} else {
self.error("unbound variable `" ++ var ++ "`")
}
}
}

fn parse_var(&self: &Parser) -> String {
let chars = [];
while self.chars.len() != 0 && self.chars.get(0).* is char && char.is_alphanumeric() {
self.chars.pop_front();
chars.push_back(char);
}
if chars.len() == 0 {
self.error("expected variable");
}
String({ chars })
}

fn expect_char(&self: &Parser, char: Char) {
self.skip_ws();
if !(self.chars.pop_front() is Some(c) && c == char) {
self.error("expected `" ++ String({ chars: [char] }) ++ "`");
}
}

fn skip_ws(&self: &Parser) {
while self.chars.len() != 0 && self.chars.get(0).*.is_whitespace() {
self.chars.pop_front();
}
}

fn error[T](&self: &Parser, error: String) -> T {
~self.error = Some(error);
move self;
~_
}
}

fn new_var(n: N32) -> String {
let chars = [];
n += 1;
while n > 0 {
n -= 1;
chars.push_front('a' + (n % 26));
n /= 26;
}
String({ chars })
}
16 changes: 8 additions & 8 deletions tests/snaps/vine/aoc_2024/day_01/compiled.iv
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,15 @@

::std::numeric::N32::ascending { fn(ref(dup2066(w2 @lt(w11 w12)) w2) fn(ref(dup2067(w5 w11) w5) w12)) }

::std::unicode::String::len { fn(ref(tup(dup2662(w2 w15) w4) tup(w2 w4)) w15) }
::std::unicode::String::len { fn(ref(tup(dup2673(w2 w15) w4) tup(w2 w4)) w15) }

::std::unicode::String::split {
fn(w2 fn(w3 w10))
::std::unicode::String::split::2 = x(w2 x(w3 x(tup(0 tup(w9 w9)) w10)))
}

::std::unicode::String::split::2 {
x(w14 x(dup2673(w1 w20) x(w12 w18)))
x(w14 x(dup2684(w1 w20) x(w12 w18)))
::std::unicode::String::split_once = fn(w14 fn(w1 tup(w3 enum(::std::unicode::String::split::6 enum(::std::unicode::String::split::7 x(w20 x(w9 w18)))))))
::std::data::List::concat = fn(w12 fn(tup(1 tup(tup(w3 w15) w15)) w9))
}
Expand All @@ -274,9 +274,9 @@
}

::std::unicode::String::split_trim::2 {
x(w24 x(dup2698(w1 w44) x(w22 x(w21 x(x(w20 w41) w39)))))
x(w24 x(dup2709(w1 w44) x(w22 x(w21 x(x(w20 w41) w39)))))
::std::unicode::String::split_once = fn(w24 fn(w1 tup(w3 enum(::std::unicode::String::split_trim::24 enum(::std::unicode::String::split_trim::25 x(w44 x(w33 x(w42 x(x(w36 w41) w39)))))))))
::std::unicode::String::len = fn(ref(w3 w7) @eq(0 dup2709(?(::std::unicode::String::split_trim::5 ::std::unicode::String::split_trim::4 x(w21 dup2702(?(::std::unicode::String::split_trim::11 ::std::unicode::String::split_trim::10 x(x(w22 w33) x(w31 x(w7 _)))) w42))) ?(::std::unicode::String::split_trim::17 ::std::unicode::String::split_trim::16 x(w36 dup2704(w20 w31))))))
::std::unicode::String::len = fn(ref(w3 w7) @eq(0 dup2720(?(::std::unicode::String::split_trim::5 ::std::unicode::String::split_trim::4 x(w21 dup2713(?(::std::unicode::String::split_trim::11 ::std::unicode::String::split_trim::10 x(x(w22 w33) x(w31 x(w7 _)))) w42))) ?(::std::unicode::String::split_trim::17 ::std::unicode::String::split_trim::16 x(w36 dup2715(w20 w31))))))
}

::std::unicode::String::split_trim::4 { x(?(0 1 w3) w3) }
Expand Down Expand Up @@ -331,7 +331,7 @@
}

::std::unicode::String::split_once::9 {
enum(ref(dup2789(w1 w16) w1) x(w9 x(w8 x(w7 x(w6 x(w5 w15))))))
enum(ref(dup2800(w1 w16) w1) x(w9 x(w8 x(w7 x(w6 x(w5 w15))))))
::std::data::List::Iter::next = fn(ref(w5 w11) enum(::std::unicode::String::split_once::13 enum(::std::unicode::String::split_once::14 x(w9 x(w8 x(w7 x(w6 x(w11 x(w16 w15)))))))))
}

Expand All @@ -340,7 +340,7 @@
::std::unicode::String::split_once::15 = x(w4 x(w3 w1))
}

::std::unicode::String::split_once::13 { enum(ref(dup2803(w1 w13) w1) x(w10 x(w9 x(w8 x(w7 x(w6 x(@ne(w13 ?(::std::unicode::String::split_once::6 ::std::unicode::String::split_once::17 x(w10 x(w9 x(w8 x(w7 x(w6 w15))))))) w15))))))) }
::std::unicode::String::split_once::13 { enum(ref(dup2814(w1 w13) w1) x(w10 x(w9 x(w8 x(w7 x(w6 x(@ne(w13 ?(::std::unicode::String::split_once::6 ::std::unicode::String::split_once::17 x(w10 x(w9 x(w8 x(w7 x(w6 w15))))))) w15))))))) }

::std::unicode::String::split_once::14 {
x(_ x(w5 x(w4 x(_ x(w2 x(_ w7))))))
Expand Down Expand Up @@ -383,7 +383,7 @@
::std::IO::print::2 = x(x(w3 w17) x(w9 w10))
}

::std::IO::print::2 { x(w4 x(dup2979(?(::std::IO::print::4 ::std::IO::print::3 x(w4 x(w6 w1))) w6) w1)) }
::std::IO::print::2 { x(w4 x(dup2990(?(::std::IO::print::4 ::std::IO::print::3 x(w4 x(w6 w1))) w6) w1)) }

::std::IO::print::3 {
x(x(w17 w21) x(@sub(1 w1) tup(w4 w5)))
Expand All @@ -402,7 +402,7 @@

::std::IO::full_input::2 {
x(x(w9 w16) x(w7 w12))
::std::IO::read_byte = fn(ref(w9 w1) fn(0 dup3073(@ne(0 ?(::std::IO::full_input::5 ::std::IO::full_input::4 x(x(w1 w16) x(w7 x(w13 w12))))) w13)))
::std::IO::read_byte = fn(ref(w9 w1) fn(0 dup3084(@ne(0 ?(::std::IO::full_input::5 ::std::IO::full_input::4 x(x(w1 w16) x(w7 x(w13 w12))))) w13)))
}

::std::IO::full_input::4 {
Expand Down
16 changes: 8 additions & 8 deletions tests/snaps/vine/aoc_2024/day_02/compiled.iv
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,15 @@

::std::numeric::N32::parse::11 { x(w10 w10) }

::std::unicode::String::len { fn(ref(tup(dup2710(w2 w15) w4) tup(w2 w4)) w15) }
::std::unicode::String::len { fn(ref(tup(dup2721(w2 w15) w4) tup(w2 w4)) w15) }

::std::unicode::String::split {
fn(w2 fn(w3 w10))
::std::unicode::String::split::2 = x(w2 x(w3 x(tup(0 tup(w9 w9)) w10)))
}

::std::unicode::String::split::2 {
x(w14 x(dup2721(w1 w20) x(w12 w18)))
x(w14 x(dup2732(w1 w20) x(w12 w18)))
::std::unicode::String::split_once = fn(w14 fn(w1 tup(w3 enum(::std::unicode::String::split::6 enum(::std::unicode::String::split::7 x(w20 x(w9 w18)))))))
::std::data::List::concat = fn(w12 fn(tup(1 tup(tup(w3 w15) w15)) w9))
}
Expand All @@ -255,9 +255,9 @@
}

::std::unicode::String::split_trim::2 {
x(w24 x(dup2746(w1 w44) x(w22 x(w21 x(x(w20 w41) w39)))))
x(w24 x(dup2757(w1 w44) x(w22 x(w21 x(x(w20 w41) w39)))))
::std::unicode::String::split_once = fn(w24 fn(w1 tup(w3 enum(::std::unicode::String::split_trim::24 enum(::std::unicode::String::split_trim::25 x(w44 x(w33 x(w42 x(x(w36 w41) w39)))))))))
::std::unicode::String::len = fn(ref(w3 w7) @eq(0 dup2757(?(::std::unicode::String::split_trim::5 ::std::unicode::String::split_trim::4 x(w21 dup2750(?(::std::unicode::String::split_trim::11 ::std::unicode::String::split_trim::10 x(x(w22 w33) x(w31 x(w7 _)))) w42))) ?(::std::unicode::String::split_trim::17 ::std::unicode::String::split_trim::16 x(w36 dup2752(w20 w31))))))
::std::unicode::String::len = fn(ref(w3 w7) @eq(0 dup2768(?(::std::unicode::String::split_trim::5 ::std::unicode::String::split_trim::4 x(w21 dup2761(?(::std::unicode::String::split_trim::11 ::std::unicode::String::split_trim::10 x(x(w22 w33) x(w31 x(w7 _)))) w42))) ?(::std::unicode::String::split_trim::17 ::std::unicode::String::split_trim::16 x(w36 dup2763(w20 w31))))))
}

::std::unicode::String::split_trim::4 { x(?(0 1 w3) w3) }
Expand Down Expand Up @@ -312,7 +312,7 @@
}

::std::unicode::String::split_once::9 {
enum(ref(dup2837(w1 w16) w1) x(w9 x(w8 x(w7 x(w6 x(w5 w15))))))
enum(ref(dup2848(w1 w16) w1) x(w9 x(w8 x(w7 x(w6 x(w5 w15))))))
::std::data::List::Iter::next = fn(ref(w5 w11) enum(::std::unicode::String::split_once::13 enum(::std::unicode::String::split_once::14 x(w9 x(w8 x(w7 x(w6 x(w11 x(w16 w15)))))))))
}

Expand All @@ -321,7 +321,7 @@
::std::unicode::String::split_once::15 = x(w4 x(w3 w1))
}

::std::unicode::String::split_once::13 { enum(ref(dup2851(w1 w13) w1) x(w10 x(w9 x(w8 x(w7 x(w6 x(@ne(w13 ?(::std::unicode::String::split_once::6 ::std::unicode::String::split_once::17 x(w10 x(w9 x(w8 x(w7 x(w6 w15))))))) w15))))))) }
::std::unicode::String::split_once::13 { enum(ref(dup2862(w1 w13) w1) x(w10 x(w9 x(w8 x(w7 x(w6 x(@ne(w13 ?(::std::unicode::String::split_once::6 ::std::unicode::String::split_once::17 x(w10 x(w9 x(w8 x(w7 x(w6 w15))))))) w15))))))) }

::std::unicode::String::split_once::14 {
x(_ x(w5 x(w4 x(_ x(w2 x(_ w7))))))
Expand Down Expand Up @@ -364,7 +364,7 @@
::std::IO::print::2 = x(x(w3 w17) x(w9 w10))
}

::std::IO::print::2 { x(w4 x(dup3027(?(::std::IO::print::4 ::std::IO::print::3 x(w4 x(w6 w1))) w6) w1)) }
::std::IO::print::2 { x(w4 x(dup3038(?(::std::IO::print::4 ::std::IO::print::3 x(w4 x(w6 w1))) w6) w1)) }

::std::IO::print::3 {
x(x(w17 w21) x(@sub(1 w1) tup(w4 w5)))
Expand All @@ -383,7 +383,7 @@

::std::IO::full_input::2 {
x(x(w9 w16) x(w7 w12))
::std::IO::read_byte = fn(ref(w9 w1) fn(0 dup3121(@ne(0 ?(::std::IO::full_input::5 ::std::IO::full_input::4 x(x(w1 w16) x(w7 x(w13 w12))))) w13)))
::std::IO::read_byte = fn(ref(w9 w1) fn(0 dup3132(@ne(0 ?(::std::IO::full_input::5 ::std::IO::full_input::4 x(x(w1 w16) x(w7 x(w13 w12))))) w13)))
}

::std::IO::full_input::4 {
Expand Down
12 changes: 6 additions & 6 deletions tests/snaps/vine/aoc_2024/day_03/compiled.iv
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,15 @@

::std::numeric::N32::parse::11 { x(w10 w10) }

::std::unicode::String::len { fn(ref(tup(dup2637(w2 w15) w4) tup(w2 w4)) w15) }
::std::unicode::String::len { fn(ref(tup(dup2648(w2 w15) w4) tup(w2 w4)) w15) }

::std::unicode::String::split {
fn(w2 fn(w3 w10))
::std::unicode::String::split::2 = x(w2 x(w3 x(tup(0 tup(w9 w9)) w10)))
}

::std::unicode::String::split::2 {
x(w14 x(dup2648(w1 w20) x(w12 w18)))
x(w14 x(dup2659(w1 w20) x(w12 w18)))
::std::unicode::String::split_once = fn(w14 fn(w1 tup(w3 enum(::std::unicode::String::split::6 enum(::std::unicode::String::split::7 x(w20 x(w9 w18)))))))
::std::data::List::concat = fn(w12 fn(tup(1 tup(tup(w3 w15) w15)) w9))
}
Expand Down Expand Up @@ -243,7 +243,7 @@
}

::std::unicode::String::split_once::9 {
enum(ref(dup2764(w1 w16) w1) x(w9 x(w8 x(w7 x(w6 x(w5 w15))))))
enum(ref(dup2775(w1 w16) w1) x(w9 x(w8 x(w7 x(w6 x(w5 w15))))))
::std::data::List::Iter::next = fn(ref(w5 w11) enum(::std::unicode::String::split_once::13 enum(::std::unicode::String::split_once::14 x(w9 x(w8 x(w7 x(w6 x(w11 x(w16 w15)))))))))
}

Expand All @@ -252,7 +252,7 @@
::std::unicode::String::split_once::15 = x(w4 x(w3 w1))
}

::std::unicode::String::split_once::13 { enum(ref(dup2778(w1 w13) w1) x(w10 x(w9 x(w8 x(w7 x(w6 x(@ne(w13 ?(::std::unicode::String::split_once::6 ::std::unicode::String::split_once::17 x(w10 x(w9 x(w8 x(w7 x(w6 w15))))))) w15))))))) }
::std::unicode::String::split_once::13 { enum(ref(dup2789(w1 w13) w1) x(w10 x(w9 x(w8 x(w7 x(w6 x(@ne(w13 ?(::std::unicode::String::split_once::6 ::std::unicode::String::split_once::17 x(w10 x(w9 x(w8 x(w7 x(w6 w15))))))) w15))))))) }

::std::unicode::String::split_once::14 {
x(_ x(w5 x(w4 x(_ x(w2 x(_ w7))))))
Expand Down Expand Up @@ -295,7 +295,7 @@
::std::IO::print::2 = x(x(w3 w17) x(w9 w10))
}

::std::IO::print::2 { x(w4 x(dup2954(?(::std::IO::print::4 ::std::IO::print::3 x(w4 x(w6 w1))) w6) w1)) }
::std::IO::print::2 { x(w4 x(dup2965(?(::std::IO::print::4 ::std::IO::print::3 x(w4 x(w6 w1))) w6) w1)) }

::std::IO::print::3 {
x(x(w17 w21) x(@sub(1 w1) tup(w4 w5)))
Expand All @@ -314,7 +314,7 @@

::std::IO::full_input::2 {
x(x(w9 w16) x(w7 w12))
::std::IO::read_byte = fn(ref(w9 w1) fn(0 dup3048(@ne(0 ?(::std::IO::full_input::5 ::std::IO::full_input::4 x(x(w1 w16) x(w7 x(w13 w12))))) w13)))
::std::IO::read_byte = fn(ref(w9 w1) fn(0 dup3059(@ne(0 ?(::std::IO::full_input::5 ::std::IO::full_input::4 x(x(w1 w16) x(w7 x(w13 w12))))) w13)))
}

::std::IO::full_input::4 {
Expand Down
Loading

0 comments on commit 08cfedd

Please sign in to comment.