about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-06-02 00:07:20 +0000
committerGitHub <noreply@github.com>2022-06-02 00:07:20 +0000
commit87d115da565618b2f2f1cbbdcca883bbc0c57e60 (patch)
treeb962cfd3ba765277e25b67fa2ec39576a1d1f589
parentedca72c160967f1918b65c91a40de89ecd8badda (diff)
downloadjinx-87d115da565618b2f2f1cbbdcca883bbc0c57e60.tar.zst
jinx-87d115da565618b2f2f1cbbdcca883bbc0c57e60.zip
OpMod and OpSetLocal for prime test
-rw-r--r--pkg/lang/vm/code/op.go2
-rw-r--r--pkg/lang/vm/exec.go55
-rw-r--r--pkg/lang/vm/text/op.go2
-rw-r--r--pkg/lang/vm/vm.go7
-rw-r--r--pkg/lang/vm/vm_test.go99
5 files changed, 164 insertions, 1 deletions
diff --git a/pkg/lang/vm/code/op.go b/pkg/lang/vm/code/op.go
index 1e501db..8b8ff3a 100644
--- a/pkg/lang/vm/code/op.go
+++ b/pkg/lang/vm/code/op.go
@@ -21,6 +21,7 @@ const (
 
 	OpGetGlobal
 	OpGetLocal
+	OpSetLocal
 	OpGetMember
 	OpSetMember
 
@@ -32,6 +33,7 @@ const (
 
 	OpAdd
 	OpSub
+	OpMod
 	OpIndex
 	OpLte
 	OpCall
diff --git a/pkg/lang/vm/exec.go b/pkg/lang/vm/exec.go
index be72158..4fbc516 100644
--- a/pkg/lang/vm/exec.go
+++ b/pkg/lang/vm/exec.go
@@ -69,6 +69,23 @@ func (vm *VM) execGetLocal(offset int) error {
 	return nil
 }
 
+func (vm *VM) execSetLocal(offset int) error {
+	new, err := vm.stack.Pop()
+	if err != nil {
+		return err
+	}
+
+	local, err := vm.stack.Local(int(offset))
+	if err != nil {
+		return err
+	}
+
+	local.Drop(vm.memory)
+
+	stackIndex := vm.stack.LocalToStackIndex(offset)
+	return vm.stack.Set(stackIndex, new)
+}
+
 func (vm *VM) execPushType(name string) error {
 	ref, err := value.NewType(vm.memory, name)
 	if err != nil {
@@ -556,6 +573,44 @@ func (vm *VM) execSub() error {
 	return nil
 }
 
+func (vm *VM) execMod() error {
+	x, err := vm.popAndDrop()
+	if err != nil {
+		return err
+	}
+	y, err := vm.popAndDrop()
+	if err != nil {
+		return err
+	}
+
+	var res value.Value
+
+	switch x.Type() {
+	case value.IntType:
+		xv := x.Data().(value.IntData).Get()
+		switch y.Type() {
+		case value.IntType:
+			yv := y.Data().(value.IntData).Get()
+			res = value.NewInt(xv % yv)
+		default:
+			return ErrInvalidOperandTypes{
+				Op: code.OpMod,
+				X:  x.Type(),
+				Y:  y.Type(),
+			}
+		}
+	default:
+		return ErrInvalidOperandTypes{
+			Op: code.OpMod,
+			X:  x.Type(),
+			Y:  y.Type(),
+		}
+	}
+
+	vm.stack.Push(res)
+	return nil
+}
+
 func (vm *VM) execIndex() error {
 	v, err := vm.popAndDrop()
 	if err != nil {
diff --git a/pkg/lang/vm/text/op.go b/pkg/lang/vm/text/op.go
index e6af940..0d01bdb 100644
--- a/pkg/lang/vm/text/op.go
+++ b/pkg/lang/vm/text/op.go
@@ -19,6 +19,7 @@ var (
 		code.OpDrop:         "drop",
 		code.OpGetGlobal:    "get_global",
 		code.OpGetLocal:     "get_local",
+		code.OpSetLocal:     "set_local",
 		code.OpGetMember:    "get_member",
 		code.OpSetMember:    "set_member",
 		code.OpGetEnv:       "get_env",
@@ -27,6 +28,7 @@ var (
 		code.OpAnchorType:   "anchor_type",
 		code.OpAdd:          "add",
 		code.OpSub:          "sub",
+		code.OpMod:          "mod",
 		code.OpIndex:        "index",
 		code.OpLte:          "lte",
 		code.OpCall:         "call",
diff --git a/pkg/lang/vm/vm.go b/pkg/lang/vm/vm.go
index 41334a6..e483176 100644
--- a/pkg/lang/vm/vm.go
+++ b/pkg/lang/vm/vm.go
@@ -125,6 +125,11 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 		vm.pc += advance
 
 		err = vm.execGetLocal(int(offset))
+	case code.OpSetLocal:
+		offset, advance := vm.code.GetInt(vm.pc)
+		vm.pc += advance
+
+		err = vm.execSetLocal(int(offset))
 	case code.OpGetMember:
 		name, advance := vm.code.GetString(vm.pc)
 		vm.pc += advance
@@ -159,6 +164,8 @@ func (vm *VM) step(op code.Op) (stepDecision, error) {
 		err = vm.execAdd()
 	case code.OpSub:
 		err = vm.execSub()
+	case code.OpMod:
+		err = vm.execMod()
 	case code.OpIndex:
 		err = vm.execIndex()
 	case code.OpLte:
diff --git a/pkg/lang/vm/vm_test.go b/pkg/lang/vm/vm_test.go
index 325f200..d63523f 100644
--- a/pkg/lang/vm/vm_test.go
+++ b/pkg/lang/vm/vm_test.go
@@ -236,7 +236,7 @@ func TestTypeConstruct(t *testing.T) {
 				this.name = name
 				this.age = age
 			}
-		
+
 			fn meow(this) {
 				return this.name + " says Meow!"
 			}
@@ -306,6 +306,103 @@ func TestTypeConstruct(t *testing.T) {
 	test(t, src, "\"Kitty says Meow!\"")
 }
 
+func TestPrimes(t *testing.T) {
+	/*
+		var i = 0
+		var primes = []
+
+		for i <= 10 {
+			var factors = []
+
+			var j = 1
+			for j <= i {
+				if i % j <= 0 {
+					factors.push(j)
+				}
+				j = j + 1
+			}
+
+			if factors.length() <= 2 {
+				primes.push(i)
+			}
+
+			i = i + 1
+		}
+
+		print(primes)
+	*/
+
+	// TODO: This test uses OpLte instead of OpEq, which works,
+	// but once OpEq is implemented, this test should be updated.
+
+	src := `
+	push_int 2
+	push_array
+	@main_loop:
+		push_int 10
+		get_local 0
+		lte
+		jf @end
+
+		push_array
+		push_int 1
+
+	@factor_loop:
+		get_local 0
+		get_local 3
+		lte
+		jf @prime_check
+
+		push_int 0
+
+		get_local 3
+		get_local 0
+		mod
+
+		lte
+		jf @factor_loop_inc
+
+		get_local 3
+		get_local 2
+		temp_arr_push
+
+	@factor_loop_inc:
+		push_int 1
+		get_local 3
+		add
+		set_local 3
+		jmp @factor_loop
+
+	@prime_check:
+		push_int 2
+		get_local 2
+		get_member "length"
+		call 0
+		lte
+
+		jf @main_loop_inc
+
+		get_local 0
+		get_local 1
+		temp_arr_push
+
+	@main_loop_inc:
+		push_int 1
+		get_local 0
+		add
+		set_local 0
+
+		drop
+		drop
+
+		jmp @main_loop
+	@end:
+		halt
+	`
+
+	test(t, src, "[2, 3, 5, 7]")
+}
+
 func test(t *testing.T, src string, expected string) {
 	bc := compile(t, src)
 	vm := vm.New(&bc)