Skip to content

Commit

Permalink
vine: the inverse operator (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjjfvi authored Oct 6, 2024
1 parent db52e2f commit 25940c4
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 12 deletions.
57 changes: 57 additions & 0 deletions tests/programs/inverse.vi
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

use std::{io::println, u32};

fn main(&io) {
refs(&io);
io.println("");
fns(&io);
io.println("");
rev(&io);
}

fn refs(&io){
let x = 0;
inc((move x, move ~x));
io.println("x = " ++ u32::to_string(x));
inc((move x, move ~x));
io.println("x = " ++ u32::to_string(x));
inc((move x, move ~x));
io.println("x = " ++ u32::to_string(x));
}

mod refs {
fn inc((init, ~fin)) {
fin = init + 1;
}
}

fn fns(&io) {
let f = { let n; (move ~n, n * n) };
io.println("f(1) = " ++ u32::to_string(call(f, 1)));
io.println("f(2) = " ++ u32::to_string(call(f, 2)));
io.println("f(3) = " ++ u32::to_string(call(f, 3)));
}

mod fns {
fn call(f, a) {
let (~i, o) = f;
i = a;
o
}
}

fn rev(&io) {
let s;
~s = "0";
io.println("s = " ++ ~s);
io.println("s = " ++ ~s);
~s = "1";
io.println("s = " ++ get(&s));
io.println("s = " ++ get(&s));
set(&s, "2");
}

mod rev {
fn get(&x) { ~x }
fn set(&x, value) { ~x = value }
}
114 changes: 114 additions & 0 deletions tests/snaps/vine/inverse/compiled.iv
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@

::main { ::inverse::main }

::inverse::main {
fn(ref(n0 n7) _)
::inverse::refs = fn(ref(n0 n1) _)
::std::io::println = fn(ref(n1 n3) fn(tup(0 fn(n2 n2)) _))
::inverse::fns = fn(ref(n3 n4) _)
::std::io::println = fn(ref(n4 n6) fn(tup(0 fn(n5 n5)) _))
::inverse::rev = fn(ref(n6 n7) _)
}

::inverse::refs {
fn(ref(n0 n9) _)
::inverse::refs::inc = fn(tup(0 dup5(n14 n15)) _)
::std::io::println = fn(ref(n0 n4) fn(n3 _))
::std::u32::to_string = fn(n14 n2)
::std::str::concat = fn(tup(4 fn(n1 tup(120 tup(32 tup(61 tup(32 n1)))))) fn(n2 n3))
::inverse::refs::inc = fn(tup(n15 dup5(n16 n17)) _)
::std::io::println = fn(ref(n4 n8) fn(n7 _))
::std::u32::to_string = fn(n16 n6)
::std::str::concat = fn(tup(4 fn(n5 tup(120 tup(32 tup(61 tup(32 n5)))))) fn(n6 n7))
::inverse::refs::inc = fn(tup(n17 n11) _)
::std::io::println = fn(ref(n8 n9) fn(n13 _))
::std::u32::to_string = fn(n11 n12)
::std::str::concat = fn(tup(4 fn(n10 tup(120 tup(32 tup(61 tup(32 n10)))))) fn(n12 n13))
}

::inverse::refs::inc { fn(tup(@add(1 n0) n0) _) }

::inverse::fns {
fn(ref(n1 n12) _)
::std::io::println = fn(ref(n1 n6) fn(n5 _))
::inverse::fns::call = fn(n18 fn(1 n3))
::std::u32::to_string = fn(n3 n4)
::std::str::concat = fn(tup(7 fn(n2 tup(102 tup(40 tup(49 tup(41 tup(32 tup(61 tup(32 n2))))))))) fn(n4 n5))
::std::io::println = fn(ref(n6 n11) fn(n10 _))
::inverse::fns::call = fn(n19 fn(2 n8))
::std::u32::to_string = fn(n8 n9)
::std::str::concat = fn(tup(7 fn(n7 tup(102 tup(40 tup(50 tup(41 tup(32 tup(61 tup(32 n7))))))))) fn(n9 n10))
::std::io::println = fn(ref(n11 n12) fn(n16 _))
::inverse::fns::call = fn(n20 fn(3 n14))
::std::u32::to_string = fn(n14 n15)
::std::str::concat = fn(tup(7 fn(n13 tup(102 tup(40 tup(51 tup(41 tup(32 tup(61 tup(32 n13))))))))) fn(n15 n16))
tup(dup13(@mul(n17 n0) n17) n0) = dup14(n18 dup14(n19 n20))
}

::inverse::fns::call { fn(tup(n0 n1) fn(n0 n1)) }

::inverse::rev {
fn(ref(n1 n15) _)
_ = tup(1 fn(n0 tup(48 n0)))
::std::io::println = fn(ref(n1 n5) fn(n4 _))
::std::str::concat = fn(tup(4 fn(n2 tup(115 tup(32 tup(61 tup(32 n2)))))) fn(n3 n4))
::std::io::println = fn(ref(n5 n10) fn(n8 _))
::std::str::concat = fn(tup(4 fn(n6 tup(115 tup(32 tup(61 tup(32 n6)))))) fn(n7 n8))
dup(dup(_ n3) n7) = tup(1 fn(n9 tup(49 n9)))
::std::io::println = fn(ref(n10 n14) fn(n13 _))
::inverse::rev::get = fn(ref(_ n17) n12)
::std::str::concat = fn(tup(4 fn(n11 tup(115 tup(32 tup(61 tup(32 n11)))))) fn(n12 n13))
::std::io::println = fn(ref(n14 n15) fn(n19 _))
::inverse::rev::get = fn(ref(n17 n20) n18)
::std::str::concat = fn(tup(4 fn(n16 tup(115 tup(32 tup(61 tup(32 n16)))))) fn(n18 n19))
::inverse::rev::set = fn(ref(n20 _) fn(tup(1 fn(n21 tup(50 n21))) _))
}

::inverse::rev::get { fn(ref(n0 dup(n0 n1)) n1) }

::inverse::rev::set { fn(ref(n0 _) fn(n0 _)) }

::std::io::println {
fn(ref(n0 n3) fn(n1 _))
::std::io::print = fn(ref(n0 n2) fn(n1 _))
::std::io::print_char = fn(ref(n2 n3) fn(10 _))
}

::std::io::print {
fn(ref(n0 n1) fn(tup(n2 fn(_ n3)) _))
::std::io::print::1 = x(n0 x(n1 x(n2 n3)))
}

::std::io::print::1 { x(n0 x(n1 x(dup42(?(::std::io::print::3 ::std::io::print::2 x(n0 x(n1 x(n3 n2)))) n3) n2))) }

::std::io::print::2 {
x(n1 x(n3 x(@sub(1 n4) tup(n0 n5))))
::std::io::print_char = fn(ref(n1 n2) fn(n0 _))
::std::io::print::1 = x(n2 x(n3 x(n4 n5)))
}

::std::io::print::3 { x(n0 x(n0 _)) }

::std::io::print_char { fn(ref(@io_print_char(char io) io) fn(char _)) }

::std::str::concat { fn(tup(@add(n0 n1) fn(n3 n4)) fn(tup(n0 fn(n2 n3)) tup(n1 fn(n2 n4)))) }

::std::u32::to_string { fn(dup176(?(::std::u32::to_string::5 ::std::u32::to_string::1 x(n1 n0)) n1) n0) }

::std::u32::to_string::1 {
x(n1 n2)
::std::u32::to_string::2 = x(n1 x(tup(0 fn(n0 n0)) n2))
}

::std::u32::to_string::2 { x(dup176(?(::std::u32::to_string::4 ::std::u32::to_string::3 x(n2 n0)) n2) n0) }

::std::u32::to_string::3 {
x(dup176(@rem(10 n1) @div(10 n5)) x(tup(@add(1 n0) fn(n3 n4)) n6))
48 = @add(n1 n2)
::std::u32::to_string::2 = x(n5 x(tup(n0 fn(n3 tup(n2 n4))) n6))
}

::std::u32::to_string::4 { x(_ x(n0 n0)) }

::std::u32::to_string::5 { x(_ tup(1 fn(n0 tup(48 n0)))) }

12 changes: 12 additions & 0 deletions tests/snaps/vine/inverse/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
x = 1
x = 2
x = 3

f(1) = 1
f(2) = 4
f(3) = 9

s = 1
s = 1
s = 2
s = 2
15 changes: 15 additions & 0 deletions tests/snaps/vine/inverse/stats.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

Interactions
Total 1_965
Annihilate 1_027
Commute 18
Copy 131
Erase 233
Expand 297
Call 170
Branch 89

Memory
Heap 1_840 B
Allocated 40_000 B
Freed 40_000 B
1 change: 1 addition & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ fn tests(t: &mut DynTester) {
test_vi(t, "vine/examples/mandelbrot.vi", b"", ".txt");

test_vi(t, "tests/programs/basic_diverge.vi", b"", ".txt");
test_vi(t, "tests/programs/inverse.vi", b"", ".txt");
test_vi(t, "tests/programs/loop_vi_loop.vi", b"", ".txt");
test_vi(t, "tests/programs/maybe_set.vi", b"", ".txt");
test_vi(t, "tests/programs/move_it_move_it.vi", b"", ".txt");
Expand Down
1 change: 1 addition & 0 deletions vine/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ pub enum TermKind {
Ref(B<Term>),
Deref(B<Term>),
Move(B<Term>),
Inverse(B<Term>),
Tuple(Vec<Term>),
List(Vec<Term>),
Field(B<Term>, Path),
Expand Down
78 changes: 67 additions & 11 deletions vine/src/compile/build_stages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ mod stage_utils;
enum ExprCtx {
Value,
Place,
Either,
Space,
ValueClear,
SpaceClone,
}

#[must_use]
enum Expr {
Value(Port),
Place(Port, Port),
Space(Port),
}

impl Compiler<'_> {
Expand Down Expand Up @@ -62,14 +65,21 @@ impl Compiler<'_> {
fn lower_expr_value(&mut self, term: &Term) -> Port {
match self.lower_expr(term, ExprCtx::Value) {
Expr::Value(t) => t,
Expr::Place(..) => unreachable!(),
_ => unreachable!(),
}
}

fn lower_expr_place(&mut self, term: &Term) -> (Port, Port) {
match self.lower_expr(term, ExprCtx::Place) {
Expr::Place(t, u) => (t, u),
Expr::Value(_) => unreachable!(),
_ => unreachable!(),
}
}

fn lower_expr_space(&mut self, term: &Term) -> Port {
match self.lower_expr(term, ExprCtx::Space) {
Expr::Space(t) => t,
_ => unreachable!(),
}
}

Expand All @@ -81,14 +91,21 @@ impl Compiler<'_> {
TermKind::Path(path) => Expr::Value(Port::Global(path.to_string())),
TermKind::Local(local) => match ctx {
ExprCtx::Value => Expr::Value(self.get_local(*local)),
ExprCtx::Place | ExprCtx::Either => {
Expr::Place(self.get_local(*local), self.set_local(*local))
ExprCtx::ValueClear => Expr::Value(self.move_local(*local)),
ExprCtx::Place => Expr::Place(self.get_local(*local), self.set_local(*local)),
ExprCtx::Space => Expr::Space(self.set_local(*local)),
ExprCtx::SpaceClone => {
let p = self.get_local(*local);
let q = self.set_local(*local);
let (x, y) = self.dup(q);
self.net.link(x, p);
Expr::Space(y)
}
},
TermKind::Assign(p, e) => {
let e = self.lower_expr_value(e);
let p = self.lower_pat_value(p);
self.net.link(e, p);
TermKind::Assign(s, v) => {
let v = self.lower_expr_value(v);
let s = self.lower_expr_space(s);
self.net.link(v, s);
Expr::Value(Port::Erase)
}
TermKind::Block(block) => Expr::Value(self.lower_block(block)),
Expand Down Expand Up @@ -142,13 +159,18 @@ impl Compiler<'_> {
}
Expr::Value(last_result)
}
TermKind::Tuple(t) => Expr::Value(self.tuple(t, Self::lower_expr_value)),
TermKind::Tuple(t) => match ctx {
ExprCtx::Value => Expr::Value(self.tuple(t, Self::lower_expr_value)),
ExprCtx::Space => Expr::Space(self.tuple(t, Self::lower_expr_space)),
_ => todo!(),
},
TermKind::String(s) => {
Expr::Value(self.list(s.chars().count(), s.chars(), |_, c| Port::U32(c as u32)))
}
TermKind::Ref(p) => Expr::Value(match self.lower_expr(p, ExprCtx::Either) {
TermKind::Ref(p) => Expr::Value(match self.lower_expr(p, ExprCtx::Place) {
Expr::Value(t) => self.new_comb("ref", t, Port::Erase),
Expr::Place(t, u) => self.new_comb("ref", t, u),
_ => unreachable!(),
}),
TermKind::List(l) => Expr::Value(self.list(l.len(), l, Self::lower_expr_value)),
TermKind::Move(t) => match t.kind {
Expand All @@ -163,6 +185,22 @@ impl Compiler<'_> {
Expr::Value(a)
}
},
TermKind::Inverse(x) => {
match self.lower_expr(
x,
match ctx {
ExprCtx::Value => ExprCtx::SpaceClone,
ExprCtx::SpaceClone => ExprCtx::Value,
ExprCtx::Place => ExprCtx::Place,
ExprCtx::Space => ExprCtx::ValueClear,
ExprCtx::ValueClear => ExprCtx::Space,
},
) {
Expr::Value(p) => Expr::Space(p),
Expr::Place(p, q) => Expr::Place(q, p),
Expr::Space(p) => Expr::Value(p),
}
}

TermKind::Fn(params, body) => self.lower_fn(params, body),
TermKind::Loop(body) => self.lower_loop(body),
Expand All @@ -186,6 +224,7 @@ impl Compiler<'_> {
let (a, b) = self.lower_pat_place(p);
self.new_comb("ref", a, b)
}
TermKind::Inverse(p) => self.lower_pat_space(p),
_ => todo!(),
}
}
Expand All @@ -200,6 +239,23 @@ impl Compiler<'_> {
(x, y.1)
}
TermKind::Move(t) => (self.lower_pat_value(t), Port::Erase),
TermKind::Inverse(x) => {
let (a, b) = self.lower_pat_place(x);
(b, a)
}
_ => todo!(),
}
}

fn lower_pat_space(&mut self, t: &Term) -> Port {
match &t.kind {
TermKind::Hole => Port::Erase,
TermKind::Local(local) => {
let x = self.net.new_wire();
self.cur.fin.push(Step::Move(*local, x.0));
x.1
}
TermKind::Inverse(x) => self.lower_pat_value(x),
_ => todo!(),
}
}
Expand Down
6 changes: 6 additions & 0 deletions vine/src/compile/build_stages/net_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,12 @@ impl Compiler<'_> {
self.cur.steps.push_back(Step::Set(local, port));
}

pub(super) fn move_local(&mut self, local: Local) -> Port {
let x = self.net.new_wire();
self.cur.steps.push_back(Step::Move(local, x.0));
x.1
}

pub(super) fn fin_move_local(&mut self, local: Local) -> Port {
let x = self.net.new_wire();
self.cur.fin.push(Step::Move(local, x.0));
Expand Down
2 changes: 2 additions & 0 deletions vine/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub enum Token {
Question,
#[token("$")]
Dollar,
#[token("~")]
Tilde,
#[token("=")]
Eq,
#[token("==")]
Expand Down
3 changes: 3 additions & 0 deletions vine/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ impl<'ctx, 'src> VineParser<'ctx, 'src> {
if self.eat(Token::Move)? {
return Ok(Term::new_move(self.parse_term_bp(BP::Prefix)?));
}
if self.eat(Token::Tilde)? {
return Ok(Term { kind: TermKind::Inverse(Box::new(self.parse_term_bp(BP::Prefix)?)) });
}
if self.eat(Token::Minus)? {
return Ok(Term::new_unary_op(UnaryOp::Neg, self.parse_term_bp(BP::Prefix)?));
}
Expand Down
Loading

0 comments on commit 25940c4

Please sign in to comment.