259 lines
5.0 KiB
Go
259 lines
5.0 KiB
Go
package vm
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/mattn/kinako/parser"
|
|
)
|
|
|
|
// Env provides interface to run VM. This mean function scope and blocked-scope.
|
|
// If stack goes to blocked-scope, it will make new Env.
|
|
type Env struct {
|
|
name string
|
|
env map[string]reflect.Value
|
|
typ map[string]reflect.Type
|
|
parent *Env
|
|
interrupt *bool
|
|
sync.RWMutex
|
|
}
|
|
|
|
// NewEnv creates new global scope.
|
|
func NewEnv() *Env {
|
|
b := false
|
|
|
|
return &Env{
|
|
env: make(map[string]reflect.Value),
|
|
typ: make(map[string]reflect.Type),
|
|
parent: nil,
|
|
interrupt: &b,
|
|
}
|
|
}
|
|
|
|
// NewEnv creates new child scope.
|
|
func (e *Env) NewEnv() *Env {
|
|
return &Env{
|
|
env: make(map[string]reflect.Value),
|
|
typ: make(map[string]reflect.Type),
|
|
parent: e,
|
|
name: e.name,
|
|
interrupt: e.interrupt,
|
|
}
|
|
}
|
|
|
|
func NewPackage(n string) *Env {
|
|
b := false
|
|
|
|
return &Env{
|
|
env: make(map[string]reflect.Value),
|
|
typ: make(map[string]reflect.Type),
|
|
parent: nil,
|
|
name: n,
|
|
interrupt: &b,
|
|
}
|
|
}
|
|
|
|
func (e *Env) NewPackage(n string) *Env {
|
|
return &Env{
|
|
env: make(map[string]reflect.Value),
|
|
typ: make(map[string]reflect.Type),
|
|
parent: e,
|
|
name: n,
|
|
interrupt: e.interrupt,
|
|
}
|
|
}
|
|
|
|
// Destroy deletes current scope.
|
|
func (e *Env) Destroy() {
|
|
e.Lock()
|
|
defer e.Unlock()
|
|
|
|
if e.parent == nil {
|
|
return
|
|
}
|
|
for k, v := range e.parent.env {
|
|
if v.IsValid() && v.Interface() == e {
|
|
delete(e.parent.env, k)
|
|
}
|
|
}
|
|
e.parent = nil
|
|
e.env = nil
|
|
}
|
|
|
|
// NewModule creates new module scope as global.
|
|
func (e *Env) NewModule(n string) *Env {
|
|
m := &Env{
|
|
env: make(map[string]reflect.Value),
|
|
parent: e,
|
|
name: n,
|
|
}
|
|
e.Define(n, m)
|
|
return m
|
|
}
|
|
|
|
// SetName sets a name of the scope. This means that the scope is module.
|
|
func (e *Env) SetName(n string) {
|
|
e.Lock()
|
|
e.name = n
|
|
e.Unlock()
|
|
}
|
|
|
|
// GetName returns module name.
|
|
func (e *Env) GetName() string {
|
|
e.RLock()
|
|
defer e.RUnlock()
|
|
|
|
return e.name
|
|
}
|
|
|
|
// Addr returns pointer value which specified symbol. It goes to upper scope until
|
|
// found or returns error.
|
|
func (e *Env) Addr(k string) (reflect.Value, error) {
|
|
e.RLock()
|
|
defer e.RUnlock()
|
|
|
|
if v, ok := e.env[k]; ok {
|
|
return v.Addr(), nil
|
|
}
|
|
if e.parent == nil {
|
|
return NilValue, fmt.Errorf("Undefined symbol '%s'", k)
|
|
}
|
|
return e.parent.Addr(k)
|
|
}
|
|
|
|
// Type returns type which specified symbol. It goes to upper scope until
|
|
// found or returns error.
|
|
func (e *Env) Type(k string) (reflect.Type, error) {
|
|
e.RLock()
|
|
defer e.RUnlock()
|
|
|
|
if v, ok := e.typ[k]; ok {
|
|
return v, nil
|
|
}
|
|
if e.parent == nil {
|
|
return NilType, fmt.Errorf("Undefined type '%s'", k)
|
|
}
|
|
return e.parent.Type(k)
|
|
}
|
|
|
|
// Get returns value which specified symbol. It goes to upper scope until
|
|
// found or returns error.
|
|
func (e *Env) Get(k string) (reflect.Value, error) {
|
|
e.RLock()
|
|
defer e.RUnlock()
|
|
|
|
if v, ok := e.env[k]; ok {
|
|
return v, nil
|
|
}
|
|
if e.parent == nil {
|
|
return NilValue, fmt.Errorf("Undefined symbol '%s'", k)
|
|
}
|
|
return e.parent.Get(k)
|
|
}
|
|
|
|
// Set modifies value which specified as symbol. It goes to upper scope until
|
|
// found or returns error.
|
|
func (e *Env) Set(k string, v interface{}) error {
|
|
e.Lock()
|
|
defer e.Unlock()
|
|
|
|
if _, ok := e.env[k]; ok {
|
|
val, ok := v.(reflect.Value)
|
|
if !ok {
|
|
val = reflect.ValueOf(v)
|
|
}
|
|
e.env[k] = val
|
|
return nil
|
|
}
|
|
if e.parent == nil {
|
|
return fmt.Errorf("Unknown symbol '%s'", k)
|
|
}
|
|
return e.parent.Set(k, v)
|
|
}
|
|
|
|
// DefineGlobal defines symbol in global scope.
|
|
func (e *Env) DefineGlobal(k string, v interface{}) error {
|
|
if e.parent == nil {
|
|
return e.Define(k, v)
|
|
}
|
|
return e.parent.DefineGlobal(k, v)
|
|
}
|
|
|
|
// DefineType defines type which specifis symbol in global scope.
|
|
func (e *Env) DefineType(k string, t interface{}) error {
|
|
if strings.Contains(k, ".") {
|
|
return fmt.Errorf("Unknown symbol '%s'", k)
|
|
}
|
|
global := e
|
|
keys := []string{k}
|
|
|
|
e.RLock()
|
|
for global.parent != nil {
|
|
if global.name != "" {
|
|
keys = append(keys, global.name)
|
|
}
|
|
global = global.parent
|
|
}
|
|
e.RUnlock()
|
|
|
|
for i, j := 0, len(keys)-1; i < j; i, j = i+1, j-1 {
|
|
keys[i], keys[j] = keys[j], keys[i]
|
|
}
|
|
|
|
typ, ok := t.(reflect.Type)
|
|
if !ok {
|
|
typ = reflect.TypeOf(t)
|
|
}
|
|
|
|
global.Lock()
|
|
global.typ[strings.Join(keys, ".")] = typ
|
|
global.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
// Define defines symbol in current scope.
|
|
func (e *Env) Define(k string, v interface{}) error {
|
|
if strings.Contains(k, ".") {
|
|
return fmt.Errorf("Unknown symbol '%s'", k)
|
|
}
|
|
val, ok := v.(reflect.Value)
|
|
if !ok {
|
|
val = reflect.ValueOf(v)
|
|
}
|
|
|
|
e.Lock()
|
|
e.env[k] = val
|
|
e.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
// String return the name of current scope.
|
|
func (e *Env) String() string {
|
|
e.RLock()
|
|
defer e.RUnlock()
|
|
|
|
return e.name
|
|
}
|
|
|
|
// Dump show symbol values in the scope.
|
|
func (e *Env) Dump() {
|
|
e.RLock()
|
|
for k, v := range e.env {
|
|
fmt.Printf("%v = %#v\n", k, v)
|
|
}
|
|
e.RUnlock()
|
|
}
|
|
|
|
// Execute parses and runs source in current scope.
|
|
func (e *Env) Execute(src string) (reflect.Value, error) {
|
|
stmts, err := parser.ParseSrc(src)
|
|
if err != nil {
|
|
return NilValue, err
|
|
}
|
|
return Run(stmts, e)
|
|
}
|