about summary refs log tree commit diff
path: root/pkg/lang/vm/value/env.go
blob: 261769918dc2ee70e79491a8fac012c68a2d073c (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
74
package value

import "jinx/pkg/lang/vm/mem"

type Env struct {
	references []reference
}

func NewEnv() Env {
	return Env{
		references: make([]reference, 0),
	}
}

func (e *Env) Allocate(m mem.Mem) (mem.Ptr, error) {
	ptr, err := m.Allocate(mem.CellKindEnv)
	if err != nil {
		return mem.NullPtr, err
	}

	if err = m.Set(ptr, EnvCell(*e)); err != nil {
		return mem.NullPtr, err
	}

	return ptr, nil
}

func (e *Env) Add(stackIndex int, outlet mem.Ptr) {
	e.references = append(e.references, reference{
		stackIndex: stackIndex,
		outlet:     outlet,
	})
}

func (e *Env) Prepend(stackIndex int, outlet mem.Ptr) {
	e.references = append([]reference{
		{
			stackIndex: stackIndex,
			outlet:     outlet,
		},
	}, e.references...)
}

func (e *Env) Clone(m mem.Mem) (Env, error) {
	cloned := NewEnv()
	for i := 0; i < e.Len(); i++ {
		differentOutlet := e.GetOutlet(i)
		if err := m.Retain(differentOutlet); err != nil {
			return Env{}, err
		}

		cloned.Add(e.GetStackIndex(i), differentOutlet)
	}
	return cloned, nil
}

// TODO: Add bounds checking

func (e *Env) GetOutlet(envIndex int) mem.Ptr {
	return e.references[envIndex].outlet
}

func (e *Env) GetStackIndex(envIndex int) int {
	return e.references[envIndex].stackIndex
}

func (e *Env) Len() int {
	return len(e.references)
}

type reference struct {
	stackIndex int
	outlet     mem.Ptr
}