#!/usr/bin/ruby

#
## Eval in an environment
#
func eval_with_x(code, x, y) {
    var f = eval(code);
    x = y;
    eval(code) - f;
}

assert_eq(24, eval_with_x('2 ** x', 3, 5));

#
## Eval with function parameter
#
func test(z) {
    z;              # use z once to avoid the warning
    eval("z+2");
}

assert_eq(42, test(40));

#
## Simple with variables
#
var (a, b) = (-5, 7);

assert_eq(abs(a * b), eval('abs(a * b)'));
assert_eq(eval '(a * b).abs', 35);

#
## Nested eval
#
assert_eq(eval '42 + eval("1 + eval(%q/1 + 1/)")', 45);

#
## Module eval
#
do {
    var foo = 42
    assert_eq(eval("foo"), 42)

    module Bar {
        var baz = 99
        assert_eq(main::foo, 42)
        assert_eq(eval("baz"), 99)
        assert_eq(eval("Bar::baz"), 99)
        assert_eq(eval("main::foo"), 42)
    }

    assert_eq(eval("Bar::baz"), 99)
    assert_eq(eval("foo"), 42)
    assert_eq(eval("main::foo"), 42)
    assert_eq(Bar::baz, 99)
}

#
## Gather/take
#
assert_eq(
    gather {
        take(3)
        eval("take(42)")
        if (true) { eval("take(\"foo\")") }
        if (false) { eval("take('bar')") }
        eval("take(99)") if (1 == 1)
    }, [3, 42, "foo", 99]
)

#
## Recursive gather/take
#
do {
    func my_fib(n) { n;
        var arr = gather {
            eval("take(n <= 1 ? n : my_fib(n-1)+my_fib(n-2))")
        }
        return arr[0]
    }
    assert_eq(8, my_fib(6))
}

#
## All done
#
say "** Test passed!";