Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vine: add lambda calculus test #165

Merged
merged 3 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading