package vm_test import ( "jinx/pkg/lang/vm" "jinx/pkg/lang/vm/code" "jinx/pkg/lang/vm/text" "strings" "testing" "github.com/stretchr/testify/require" ) func TestSimpleSub(t *testing.T) { src := ` push_int 1 push_int 2 sub ` test(t, src, "1") } func TestGetLocal(t *testing.T) { src := ` push_int 404 push_int 1 push_int 2 add get_local 1 ` test(t, src, "3") } func TestFibonacci(t *testing.T) { src := ` # Array stored in local 0 push_array push_int 1 get_local 0 temp_arr_push push_int 1 get_local 0 temp_arr_push @fib_loop: push_int 1 get_local 0 temp_arr_len # Index of the last element stored in local 1 sub # This is the last element get_local 1 get_local 0 # Store the last element in local 2 index push_int 1 get_local 1 # Index of the second last element stored in local 2 sub get_local 0 # Store the second last element in local 3 index add get_local 0 temp_arr_push # Drop local 1, which was the length of the array, which we no longer need drop push_int 10 get_local 0 temp_arr_len # Jump if the array is larger than 10. lte jt @fib_loop ` test(t, src, "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]") } func TestFunction(t *testing.T) { src := ` push_int 44 push_function @subtract_two call halt @subtract_two: shift 1 push_int 2 get_local 0 sub ret ` test(t, src, "42") } func TestSimpleEnv(t *testing.T) { src := ` push_int 404 push_int 1 push_int 405 push_function @test # Add the local 1 to the environment. add_to_env 1 call halt @test: push_int 2 get_env 0 add ret ` test(t, src, "3") } func TestEscapedEnv(t *testing.T) { /* fn create() { var x = 0 return fn () { x = x + 1 return x } } var f = create() var res = [f(), f(), f()] */ src := ` push_function @create call push_array get_local 0 call get_local 1 temp_arr_push get_local 0 call get_local 1 temp_arr_push get_local 0 call get_local 1 temp_arr_push halt @create: push_int 0 push_int 404 push_int 405 push_function @create:anon_0 add_to_env 0 ret @create:anon_0: push_int 1 get_env 0 add set_env 0 get_env 0 ret ` test(t, src, "[1, 2, 3]") } func TestMember(t *testing.T) { src := ` push_array push_int 1 get_local 0 temp_arr_push push_int 2 get_local 0 temp_arr_push push_int 3 get_local 0 temp_arr_push get_member "length" call ` test(t, src, "3") } func test(t *testing.T, src string, expected string) { bc := compile(t, src) vm := vm.New(&bc) err := vm.Run() require.NoError(t, err) res, err := vm.GetResult() require.NoError(t, err) require.Equal(t, expected, res) } func compile(t *testing.T, src string) code.Code { comp := text.NewCompiler(strings.NewReader(src)) bc, err := comp.Compile() require.NoErrorf(t, err, "compilation from text format failed: %s", err) return bc }