0440786b8d
* fixes #193 * Cleanup
298 lines
7 KiB
Go
298 lines
7 KiB
Go
package runtime_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/d5/tengo/objects"
|
|
)
|
|
|
|
func TestFunction(t *testing.T) {
|
|
// function with no "return" statement returns "invalid" value.
|
|
expect(t, `f1 := func() {}; out = f1();`, nil, objects.UndefinedValue)
|
|
expect(t, `f1 := func() {}; f2 := func() { return f1(); }; f1(); out = f2();`, nil, objects.UndefinedValue)
|
|
expect(t, `f := func(x) { x; }; out = f(5);`, nil, objects.UndefinedValue)
|
|
|
|
expect(t, `f := func(...x) { return x; }; out = f(1,2,3);`, nil, ARR{1, 2, 3})
|
|
|
|
expect(t, `f := func(a, b, ...x) { return [a, b, x]; }; out = f(8,9,1,2,3);`, nil, ARR{8, 9, ARR{1, 2, 3}})
|
|
|
|
expect(t, `f := func(v) { x := 2; return func(a, ...b){ return [a, b, v+x]}; }; out = f(5)("a", "b");`, nil,
|
|
ARR{"a", ARR{"b"}, 7})
|
|
|
|
expect(t, `f := func(...x) { return x; }; out = f();`, nil, &objects.Array{Value: []objects.Object{}})
|
|
|
|
expect(t, `f := func(a, b, ...x) { return [a, b, x]; }; out = f(8, 9);`, nil,
|
|
ARR{8, 9, ARR{}})
|
|
|
|
expect(t, `f := func(v) { x := 2; return func(a, ...b){ return [a, b, v+x]}; }; out = f(5)("a");`, nil,
|
|
ARR{"a", ARR{}, 7})
|
|
|
|
expectError(t, `f := func(a, b, ...x) { return [a, b, x]; }; f();`, nil,
|
|
"Runtime Error: wrong number of arguments: want>=2, got=0\n\tat test:1:46")
|
|
|
|
expectError(t, `f := func(a, b, ...x) { return [a, b, x]; }; f(1);`, nil,
|
|
"Runtime Error: wrong number of arguments: want>=2, got=1\n\tat test:1:46")
|
|
|
|
expect(t, `f := func(x) { return x; }; out = f(5);`, nil, 5)
|
|
expect(t, `f := func(x) { return x * 2; }; out = f(5);`, nil, 10)
|
|
expect(t, `f := func(x, y) { return x + y; }; out = f(5, 5);`, nil, 10)
|
|
expect(t, `f := func(x, y) { return x + y; }; out = f(5 + 5, f(5, 5));`, nil, 20)
|
|
expect(t, `out = func(x) { return x; }(5)`, nil, 5)
|
|
expect(t, `x := 10; f := func(x) { return x; }; f(5); out = x;`, nil, 10)
|
|
|
|
expect(t, `
|
|
f2 := func(a) {
|
|
f1 := func(a) {
|
|
return a * 2;
|
|
};
|
|
|
|
return f1(a) * 3;
|
|
};
|
|
|
|
out = f2(10);
|
|
`, nil, 60)
|
|
|
|
expect(t, `
|
|
f1 := func(f) {
|
|
a := [undefined]
|
|
a[0] = func() { return f(a) }
|
|
return a[0]()
|
|
}
|
|
|
|
out = f1(func(a) { return 2 })
|
|
`, nil, 2)
|
|
|
|
// closures
|
|
expect(t, `
|
|
newAdder := func(x) {
|
|
return func(y) { return x + y };
|
|
};
|
|
|
|
add2 := newAdder(2);
|
|
out = add2(5);
|
|
`, nil, 7)
|
|
|
|
// function as a argument
|
|
expect(t, `
|
|
add := func(a, b) { return a + b };
|
|
sub := func(a, b) { return a - b };
|
|
applyFunc := func(a, b, f) { return f(a, b) };
|
|
|
|
out = applyFunc(applyFunc(2, 2, add), 3, sub);
|
|
`, nil, 1)
|
|
|
|
expect(t, `f1 := func() { return 5 + 10; }; out = f1();`, nil, 15)
|
|
expect(t, `f1 := func() { return 1 }; f2 := func() { return 2 }; out = f1() + f2()`, nil, 3)
|
|
expect(t, `f1 := func() { return 1 }; f2 := func() { return f1() + 2 }; f3 := func() { return f2() + 3 }; out = f3()`, nil, 6)
|
|
expect(t, `f1 := func() { return 99; 100 }; out = f1();`, nil, 99)
|
|
expect(t, `f1 := func() { return 99; return 100 }; out = f1();`, nil, 99)
|
|
expect(t, `f1 := func() { return 33; }; f2 := func() { return f1 }; out = f2()();`, nil, 33)
|
|
expect(t, `one := func() { one = 1; return one }; out = one()`, nil, 1)
|
|
expect(t, `three := func() { one := 1; two := 2; return one + two }; out = three()`, nil, 3)
|
|
expect(t, `three := func() { one := 1; two := 2; return one + two }; seven := func() { three := 3; four := 4; return three + four }; out = three() + seven()`, nil, 10)
|
|
expect(t, `
|
|
foo1 := func() {
|
|
foo := 50
|
|
return foo
|
|
}
|
|
foo2 := func() {
|
|
foo := 100
|
|
return foo
|
|
}
|
|
out = foo1() + foo2()`, nil, 150)
|
|
expect(t, `
|
|
g := 50;
|
|
minusOne := func() {
|
|
n := 1;
|
|
return g - n;
|
|
};
|
|
minusTwo := func() {
|
|
n := 2;
|
|
return g - n;
|
|
};
|
|
out = minusOne() + minusTwo()
|
|
`, nil, 97)
|
|
expect(t, `
|
|
f1 := func() {
|
|
f2 := func() { return 1; }
|
|
return f2
|
|
};
|
|
out = f1()()
|
|
`, nil, 1)
|
|
|
|
expect(t, `
|
|
f1 := func(a) { return a; };
|
|
out = f1(4)`, nil, 4)
|
|
expect(t, `
|
|
f1 := func(a, b) { return a + b; };
|
|
out = f1(1, 2)`, nil, 3)
|
|
|
|
expect(t, `
|
|
sum := func(a, b) {
|
|
c := a + b;
|
|
return c;
|
|
};
|
|
out = sum(1, 2);`, nil, 3)
|
|
|
|
expect(t, `
|
|
sum := func(a, b) {
|
|
c := a + b;
|
|
return c;
|
|
};
|
|
out = sum(1, 2) + sum(3, 4);`, nil, 10)
|
|
|
|
expect(t, `
|
|
sum := func(a, b) {
|
|
c := a + b
|
|
return c
|
|
};
|
|
outer := func() {
|
|
return sum(1, 2) + sum(3, 4)
|
|
};
|
|
out = outer();`, nil, 10)
|
|
|
|
expect(t, `
|
|
g := 10;
|
|
|
|
sum := func(a, b) {
|
|
c := a + b;
|
|
return c + g;
|
|
}
|
|
|
|
outer := func() {
|
|
return sum(1, 2) + sum(3, 4) + g;
|
|
}
|
|
|
|
out = outer() + g
|
|
`, nil, 50)
|
|
|
|
expectError(t, `func() { return 1; }(1)`, nil, "wrong number of arguments")
|
|
expectError(t, `func(a) { return a; }()`, nil, "wrong number of arguments")
|
|
expectError(t, `func(a, b) { return a + b; }(1)`, nil, "wrong number of arguments")
|
|
|
|
expect(t, `
|
|
f1 := func(a) {
|
|
return func() { return a; };
|
|
};
|
|
f2 := f1(99);
|
|
out = f2()
|
|
`, nil, 99)
|
|
|
|
expect(t, `
|
|
f1 := func(a, b) {
|
|
return func(c) { return a + b + c };
|
|
};
|
|
|
|
f2 := f1(1, 2);
|
|
out = f2(8);
|
|
`, nil, 11)
|
|
expect(t, `
|
|
f1 := func(a, b) {
|
|
c := a + b;
|
|
return func(d) { return c + d };
|
|
};
|
|
f2 := f1(1, 2);
|
|
out = f2(8);
|
|
`, nil, 11)
|
|
expect(t, `
|
|
f1 := func(a, b) {
|
|
c := a + b;
|
|
return func(d) {
|
|
e := d + c;
|
|
return func(f) { return e + f };
|
|
}
|
|
};
|
|
f2 := f1(1, 2);
|
|
f3 := f2(3);
|
|
out = f3(8);
|
|
`, nil, 14)
|
|
expect(t, `
|
|
a := 1;
|
|
f1 := func(b) {
|
|
return func(c) {
|
|
return func(d) { return a + b + c + d }
|
|
};
|
|
};
|
|
f2 := f1(2);
|
|
f3 := f2(3);
|
|
out = f3(8);
|
|
`, nil, 14)
|
|
expect(t, `
|
|
f1 := func(a, b) {
|
|
one := func() { return a; };
|
|
two := func() { return b; };
|
|
return func() { return one() + two(); }
|
|
};
|
|
f2 := f1(9, 90);
|
|
out = f2();
|
|
`, nil, 99)
|
|
|
|
// global function recursion
|
|
expect(t, `
|
|
fib := func(x) {
|
|
if x == 0 {
|
|
return 0
|
|
} else if x == 1 {
|
|
return 1
|
|
} else {
|
|
return fib(x-1) + fib(x-2)
|
|
}
|
|
}
|
|
out = fib(15)`, nil, 610)
|
|
|
|
// local function recursion
|
|
expect(t, `
|
|
out = func() {
|
|
sum := func(x) {
|
|
return x == 0 ? 0 : x + sum(x-1)
|
|
}
|
|
return sum(5)
|
|
}()`, nil, 15)
|
|
|
|
expectError(t, `return 5`, nil, "return not allowed outside function")
|
|
|
|
// closure and block scopes
|
|
expect(t, `
|
|
func() {
|
|
a := 10
|
|
func() {
|
|
b := 5
|
|
if true {
|
|
out = a + 5
|
|
}
|
|
}()
|
|
}()`, nil, 15)
|
|
expect(t, `
|
|
func() {
|
|
a := 10
|
|
b := func() { return 5 }
|
|
func() {
|
|
if b() {
|
|
out = a + b()
|
|
}
|
|
}()
|
|
}()`, nil, 15)
|
|
expect(t, `
|
|
func() {
|
|
a := 10
|
|
func() {
|
|
b := func() { return 5 }
|
|
func() {
|
|
if true {
|
|
out = a + b()
|
|
}
|
|
}()
|
|
}()
|
|
}()`, nil, 15)
|
|
|
|
// function skipping return
|
|
expect(t, `out = func() {}()`, nil, objects.UndefinedValue)
|
|
expect(t, `out = func(v) { if v { return true } }(1)`, nil, true)
|
|
expect(t, `out = func(v) { if v { return true } }(0)`, nil, objects.UndefinedValue)
|
|
expect(t, `out = func(v) { if v { } else { return true } }(1)`, nil, objects.UndefinedValue)
|
|
expect(t, `out = func(v) { if v { return } }(1)`, nil, objects.UndefinedValue)
|
|
expect(t, `out = func(v) { if v { return } }(0)`, nil, objects.UndefinedValue)
|
|
expect(t, `out = func(v) { if v { } else { return } }(1)`, nil, objects.UndefinedValue)
|
|
expect(t, `out = func(v) { for ;;v++ { if v == 3 { return true } } }(1)`, nil, true)
|
|
expect(t, `out = func(v) { for ;;v++ { if v == 3 { break } } }(1)`, nil, objects.UndefinedValue)
|
|
}
|