about summary refs log tree commit diff
path: root/pkg/lang/vm/text/compiler_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lang/vm/text/compiler_test.go')
-rw-r--r--pkg/lang/vm/text/compiler_test.go164
1 files changed, 164 insertions, 0 deletions
diff --git a/pkg/lang/vm/text/compiler_test.go b/pkg/lang/vm/text/compiler_test.go
new file mode 100644
index 0000000..cf2f6a9
--- /dev/null
+++ b/pkg/lang/vm/text/compiler_test.go
@@ -0,0 +1,164 @@
+package text_test
+
+import (
+	"encoding/binary"
+	"jinx/pkg/lang/vm/code"
+	"jinx/pkg/lang/vm/text"
+	"math"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestSimple(t *testing.T) {
+	src := `
+	get_arg
+	get_arg
+	sub
+	ret
+	`
+
+	c := text.NewCompiler(strings.NewReader(src))
+	res, err := c.Compile()
+	require.NoError(t, err)
+
+	parts := [][]byte{
+		opBin(code.OpGetArg),
+		opBin(code.OpGetArg),
+		opBin(code.OpSub),
+		opBin(code.OpRet),
+	}
+
+	require.Equal(t, joinSlices(parts), res.Code())
+}
+
+func TestInt(t *testing.T) {
+	src := `
+	push_int 1
+	push_int 2
+	add
+	ret
+	`
+
+	c := text.NewCompiler(strings.NewReader(src))
+	res, err := c.Compile()
+	require.NoError(t, err)
+
+	parts := [][]byte{
+		opBin(code.OpPushInt),
+		uintBin(1),
+		opBin(code.OpPushInt),
+		uintBin(2),
+		opBin(code.OpAdd),
+		opBin(code.OpRet),
+	}
+
+	require.Equal(t, joinSlices(parts), res.Code())
+}
+
+func TestFloat(t *testing.T) {
+	src := `
+	push_float 3.1415
+	push_float -2.71828
+	`
+
+	c := text.NewCompiler(strings.NewReader(src))
+	res, err := c.Compile()
+	require.NoError(t, err)
+
+	parts := [][]byte{
+		opBin(code.OpPushFloat),
+		floatBin(3.1415),
+		opBin(code.OpPushFloat),
+		floatBin(-2.71828),
+	}
+
+	require.Equal(t, joinSlices(parts), res.Code())
+}
+
+func TestString(t *testing.T) {
+	src := `
+	push_string "Hello, "
+	push_string "world!"
+	add
+	`
+
+	c := text.NewCompiler(strings.NewReader(src))
+	res, err := c.Compile()
+	require.NoError(t, err)
+
+	parts := [][]byte{
+		opBin(code.OpPushString),
+		stringBin("Hello, "),
+		opBin(code.OpPushString),
+		stringBin("world!"),
+		opBin(code.OpAdd),
+	}
+
+	require.Equal(t, joinSlices(parts), res.Code())
+}
+
+func TestLabels(t *testing.T) {
+	src := `
+	@1:
+		nop
+	@2:
+		nop
+	@3:
+		nop
+		jmp @1
+		jmp @2
+		jmp @3
+	`
+
+	c := text.NewCompiler(strings.NewReader(src))
+	res, err := c.Compile()
+	require.NoError(t, err)
+
+	parts := [][]byte{
+		opBin(code.OpNop),
+		opBin(code.OpNop),
+		opBin(code.OpNop),
+		opBin(code.OpJmp),
+		uintBin(0),
+		opBin(code.OpJmp),
+		uintBin(1),
+		opBin(code.OpJmp),
+		uintBin(2),
+	}
+
+	require.Equal(t, joinSlices(parts), res.Code())
+}
+
+func opBin(op code.Op) []byte {
+	return []byte{byte(op)}
+}
+
+func uintBin(x uint64) []byte {
+	res := make([]byte, 8)
+	binary.LittleEndian.PutUint64(res, x)
+	return res
+}
+
+func floatBin(x float64) []byte {
+	res := make([]byte, 8)
+	binary.LittleEndian.PutUint64(res, math.Float64bits(x))
+	return res
+}
+
+func stringBin(x string) []byte {
+	res := []byte(x)
+	res = append(res, 0)
+	return res
+}
+
+func joinSlices[T any](slices [][]T) []T {
+	res := []T{}
+
+	for _, slice := range slices {
+		res = append(res, slice...)
+	}
+
+	return res
+}