fungi-lang 0.1.63

Fungi: A typed, functional language for programs that name their cached dependency graphs
Documentation
#![recursion_limit="128"]
#[macro_use]
extern crate fungi_lang;
extern crate adapton;

use std::rc::Rc;
use fungi_lang::ast::*;
use fungi_lang::eval;
use fungi_lang::reduce;
use fungi_lang::dynamics;
use fungi_lang::vis;


fn eval_closed_exp(e:Exp) -> dynamics::ExpTerm {
    eval::eval(dynamics::env_emp(), e)
}

fn reduce_closed_exp(e:Exp) -> dynamics::ExpTerm {
    reduce::reduce_db(vec![], dynamics::env_emp(), e)
}

fn eval_test_equiv(e1:Exp, e2:Exp) {
    //println!("> {:?}\n\n", e1);

    let eval_t1 = eval_closed_exp(e1.clone());
    let eval_t2 = eval_closed_exp(e2.clone());
    assert_eq!(eval_t1, eval_t2);

    let red_t1 = reduce_closed_exp(e1);
    let red_t2 = reduce_closed_exp(e2);
    assert_eq!(red_t1, red_t2);

    // Evaluation and reduction are equivalent:
    assert_eq!(eval_t1, red_t1);
    assert_eq!(eval_t2, red_t2);
}

#[test]
fn eval_force_anon_thunk () {
    eval_test_equiv(
        fgi_exp![
            let x = {ret 1}
            let y = {ret 2}
            let t = {ret thunk x + y}
            {force t}
        ],
        fgi_exp![
            ret 3
        ])        
}

#[test]
fn eval_let_pair_natlt () {
    eval_test_equiv(
        fgi_exp![
            let pair  = {ret (1, 2)}
            let (x,y) = {ret pair}
            x < y
        ],
        fgi_exp![
            ret true
        ])
}

#[test]
fn eval_lambda_app () {
    eval_test_equiv(
        fgi_exp![
            {#x.#y.x < y} 1 2
        ],
        fgi_exp![
            ret true
        ]);

    eval_test_equiv(
        fgi_exp![
            let x = {{#x.#y.x + y} 1 2}
            {#z1.#z2.#z3. if {z1 < z2} {ret 123} else {ret 321}}
            x 4 666
        ],
        fgi_exp![
            ret 123
        ]);
}

#[test]
fn eval_case () {
    eval_test_equiv(
        fgi_exp![
            match (inj1 2) {
                x => {x + 1}
                y => {ret 0}
            }
        ],
        fgi_exp![
            ret 3
        ]);
    
    eval_test_equiv(
        fgi_exp![
            match (inj2 6) {
                x => {x + 1}
                y => {ret 3}
            }
        ],
        fgi_exp![
            ret 3
        ]);

    // test nested cases; nested injections are a little awkward
    eval_test_equiv(
        fgi_exp![
            match (inj2 (inj2 7)) {
                x => {ret 1}
                x => {ret 2}
                y => {ret y}
            }
        ],
        fgi_exp![
            ret 7
        ])
}

#[test]
fn eval_fix () {
    eval_test_equiv(
        fgi_exp![
            let rec f:(Thk[0] Nat -> (Nat -> (F Nat |> {0;0}) |> {0;0}) {0;0}) = {
                #x. if {x == 0} {ret 123} else {ret 321}
            }
            {force f} 0
        ],
        fgi_exp![
            ret 123
        ]);
        
    eval_test_equiv(
        fgi_exp![
            let rec f:(Thk[0] Nat -> (Nat -> (F Nat |> {0;0}) |> {0;0}) {0;0}) = {
                #x. if {x == 0} {{force f} 1} else {ret 321}
            }
            {force f} 0
        ],
        fgi_exp![
            ret 321
        ]);

    eval_test_equiv(
        fgi_exp![
            let rec f:(Thk[0] Nat -> (Nat -> (F Nat |> {0;0}) |> {0;0}) {0;0}) = {
                #x. if {x == 0} {let x = {x + 1} {force f} x} else {ret x}
            }
            {force f} 0
        ],
        fgi_exp![
            ret 1
        ]);

    eval_test_equiv(
        fgi_exp![
            let rec f:(Thk[0] Nat -> (Nat -> (F Nat |> {0;0}) |> {0;0}) {0;0}) = {
                #x. #end. if {x < end} {let x = {x + 1} {force f} x end} else {ret x}
            }
            {force f} 0 2
        ],
        fgi_exp![
            ret 2
        ])      

}

#[test]
fn trace_simple() {
    let exp = fgi_exp![
        let pair  = {ret (1, 2)}
        let (x,y) = {ret pair}
        x < y
    ];
    
    let vis_exp = vis::label_exp(exp, &mut 0);
    println!("Exp: {:?}\n\n", vis_exp);
    
    let (_term, traces) = vis::capture_traces(|| eval_closed_exp(vis_exp));
    println!("Traces: {:?}\n\n", traces);
    
    assert_eq!(traces.len(), 6);
}