about summary refs log tree commit diff
path: root/pkg/lang/vm/utils.go
blob: a40a14f36924bede071db8e5747824b6b4689c05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package vm

import (
	"jinx/pkg/lang/vm/mem"
	"jinx/pkg/lang/vm/value"
)

func (vm *VM) popAndDrop() (value.Value, error) {
	v, err := vm.stack.Pop()
	if err != nil {
		return value.Value{}, err
	}
	v.Drop(vm.memory)
	return v, nil
}

func (vm *VM) popCallAndDrop() (int, error) {
	envPtr := vm.stack.CurrentCallEnv()
	vm.memory.Release(envPtr)

	for !vm.stack.ReachedBaseOfCall() {
		_, err := vm.popAndDrop()
		if err != nil {
			return 0, err
		}
	}

	return vm.stack.PopCall()
}

func (vm *VM) getMemCell(ptr mem.Ptr, kind mem.CellKind, allowNil bool) (mem.CellData, error) {
	if ptr.IsNull() {
		return nil, ErrEnvNotSet
	}

	if !vm.memory.Is(ptr, kind) {
		return nil, ErrUnexpectedMemCell{Ptr: ptr, Expected: mem.CellKindEnv, Got: vm.memory.Kind(ptr)}
	}

	cell, err := vm.memory.Get(ptr)
	if err != nil {
		return nil, err
	}

	if cell == nil {
		if allowNil {
			return nil, nil
		}
		return nil, ErrMemNilCell{Ptr: ptr}
	}

	ok := false
	switch kind {
	case mem.CellKindString:
		_, ok = cell.(value.StringCell)
	case mem.CellKindArray:
		_, ok = cell.(value.ArrayCell)
	case mem.CellKindEnv:
		_, ok = cell.(value.EnvCell)
	case mem.CellKindOutlet:
		_, ok = cell.(value.OutletCell)
	case mem.CellKindType:
		_, ok = cell.(value.TypeCell)
	case mem.CellKindObject:
		_, ok = cell.(value.ObjectCell)
	}

	if !ok {
		return nil, ErrCorruptedMemCell{Ptr: ptr}
	}

	return cell, nil
}