80 lines
1.5 KiB
Go
80 lines
1.5 KiB
Go
|
package scripting
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
|
||
|
"git.kirsle.net/apps/doodle/lib/render"
|
||
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||
|
"github.com/robertkrimen/otto"
|
||
|
)
|
||
|
|
||
|
// VM manages a single isolated JavaScript VM.
|
||
|
type VM struct {
|
||
|
Name string
|
||
|
|
||
|
// Globals available to the scripts.
|
||
|
Events *Events
|
||
|
Self interface{}
|
||
|
|
||
|
vm *otto.Otto
|
||
|
}
|
||
|
|
||
|
// NewVM creates a new JavaScript VM.
|
||
|
func NewVM(name string) *VM {
|
||
|
vm := &VM{
|
||
|
Name: name,
|
||
|
Events: NewEvents(),
|
||
|
vm: otto.New(),
|
||
|
}
|
||
|
return vm
|
||
|
}
|
||
|
|
||
|
// Run code in the VM.
|
||
|
func (vm *VM) Run(src interface{}) (otto.Value, error) {
|
||
|
v, err := vm.vm.Run(src)
|
||
|
return v, err
|
||
|
}
|
||
|
|
||
|
// Set a value in the VM.
|
||
|
func (vm *VM) Set(name string, v interface{}) error {
|
||
|
return vm.vm.Set(name, v)
|
||
|
}
|
||
|
|
||
|
// RegisterLevelHooks registers accessors to the level hooks
|
||
|
// and Doodad API for Play Mode.
|
||
|
func (vm *VM) RegisterLevelHooks() error {
|
||
|
bindings := map[string]interface{}{
|
||
|
"log": log.Logger,
|
||
|
"RGBA": render.RGBA,
|
||
|
"Point": render.NewPoint,
|
||
|
"Self": vm.Self,
|
||
|
"Events": vm.Events,
|
||
|
}
|
||
|
for name, v := range bindings {
|
||
|
err := vm.vm.Set(name, v)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("RegisterLevelHooks(%s): %s",
|
||
|
name, err,
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
vm.vm.Run(`console = {}; console.log = log.Info;`)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Main calls the main function of the script.
|
||
|
func (vm *VM) Main() error {
|
||
|
function, err := vm.vm.Get("main")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if !function.IsFunction() {
|
||
|
return errors.New("main is not a function")
|
||
|
}
|
||
|
|
||
|
_, err = function.Call(otto.Value{})
|
||
|
return err
|
||
|
}
|