about summary refs log tree commit diff
path: root/pkg/lang/vm/setup.go
blob: 201538dd169789441a2e3bcad570c518e5621a4d (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
package vm

import (
	"fmt"
	"jinx/pkg/lang/modules"
	"jinx/pkg/lang/modules/core"
	"jinx/pkg/lang/modules/natives"
	"jinx/pkg/lang/vm/value"
)

func (vm *VM) setup() error {
	vm.modules = make([]modules.Module, 0, len(vm.main.Deps()))

	// Add all natives to the VM as globals.
	for _, native := range natives.Natives {
		decollidedName := fmt.Sprintf("%s#native", native.Name)

		if _, ok := vm.globals[decollidedName]; ok {
			return fmt.Errorf("native %s already exists", decollidedName)
		}

		nativeFunc := native.Fn // Capture the native function, because Go is fun.
		wrappedFunc := func(args []value.Value) (value.Value, error) {
			return nativeFunc(vm, args)
		}

		nativeFunction := value.NewNativeFunction(wrappedFunc, uint(native.ArgCount))
		if err := vm.AddGlobal(decollidedName, nativeFunction); err != nil {
			return err
		}
	}

	for _, depRef := range vm.main.Deps() {
		dep, err := vm.resolveModule(depRef)
		if err != nil {
			return err
		}

		vm.modules = append(vm.modules, dep)
	}

	return nil
}

// TODO: Make an actual module resolver.
func (vm *VM) resolveModule(ref modules.ModuleRef) (modules.Module, error) {
	// TODO: Support other modules than core.
	switch ref.Name() {
	case "core":
		return core.Module, nil
	default:
		return modules.Module{}, fmt.Errorf("unknown module: %s", ref.Name())
	}
}