vm

package
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 9, 2018 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package vm implements virtual-machine for anko.

Example (VmBasicOperators)
package main

import (
	"fmt"
	"log"

	"github.com/mattn/anko/vm"
)

func main() {
	env := vm.NewEnv()

	err := env.Define("println", fmt.Println)
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}

	script := `
a = nil
println(a)
a = true
println(a)

println("")

a = 2 + 1
println(a)
a = 2 - 1
println(a)
a = 2 * 1
println(a)
a = 4 / 2
println(a)

println("")

a = 1
a++
println(a)
a--
println(a)

println("")

a = 1
a += 1
println(a)
a -= 1
println(a)
a *= 4
println(a)
a /= 2
println(a)

println("")

a = 2 ** 3
println(a)
a = 1 & 3
println(a)
a = 1 | 2
println(a) 

println("")

a = 2 << 3
println(a)
a = 8 >> 2
println(a)
a = 7 % 3
println(a)

println("")

a = 2 - (-2)
println(a)
a = ^2
println(a)
a = "a" * 4
println(a)
a = !true
println(a)

`

	_, err = env.Execute(script)
	if err != nil {
		log.Fatalf("execute error: %v\n", err)
	}

}
Output:

<nil>
true

3
1
2
2

2
1

2
1
4
2

8
1
3

16
2
1

4
-3
aaaa
false
Example (VmComparisonOperators)
package main

import (
	"fmt"
	"log"

	"github.com/mattn/anko/vm"
)

func main() {
	env := vm.NewEnv()

	err := env.Define("println", fmt.Println)
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}

	script := `
a = nil == nil
println(a)
a = "a" != "a" 
println(a)
a = 1 == 1.0
println(a)
a = !true
println(a)

println("")

a = 1 < 2
println(a)
a = 1 > 3
println(a)
a = 2 <= 2
println(a)
a = 2 >= 3
println(a)

println("")
a = 1 == 2 && 1 == 1
println(a)
a = 1 == 2 || 1 == 1
println(a)
`

	_, err = env.Execute(script)
	if err != nil {
		log.Fatalf("execute error: %v\n", err)
	}

}
Output:

true
false
true
false

true
false
true
false

false
true
Example (VmHelloWorld)
package main

import (
	"fmt"
	"log"

	"github.com/mattn/anko/vm"
)

func main() {
	env := vm.NewEnv()

	err := env.Define("println", fmt.Println)
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}

	script := `
println("Hello World :)")
`

	_, err = env.Execute(script)
	if err != nil {
		log.Fatalf("execute error: %v\n", err)
	}

}
Output:

Hello World :)
Example (VmModule)
package main

import (
	"fmt"
	"log"

	"github.com/mattn/anko/vm"
)

func main() {
	env := vm.NewEnv()

	err := env.Define("println", fmt.Println)
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}

	script := `
module rectangle {
	_length = 1
	_width = 1
	
	func setLength (length) {
		if length <= 0 {
			return
		}
		_length = length
	}
	
	func setWidth (width) {
		if width <= 0 {
			return
		}
		_width = width
	}
	
	func area () {
		return _length * _width
	}
	
	func perimeter () {
		return 2 * (_length + _width)
	}
 }

rectangle1 = rectangle

rectangle1.setLength(4)
rectangle1.setWidth(5)

println(rectangle1.area())
println(rectangle1.perimeter())

rectangle2 = rectangle

rectangle2.setLength(2)
rectangle2.setWidth(4)

println(rectangle2.area())
println(rectangle2.perimeter())
`

	_, err = env.Execute(script)
	if err != nil {
		log.Fatalf("execute error: %v\n", err)
	}

}
Output:

20
18
8
12
Example (VmSort)
package main

import (
	"log"

	"github.com/mattn/anko/packages"
	"github.com/mattn/anko/vm"
)

func main() {
	env := vm.NewEnv()
	packages.DefineImport(env)

	script := `
fmt = import("fmt")
sort = import("sort")
a = [5, 1.1, 3, "f", "2", "4.4"]
sortFuncs = make(sort.SortFuncsStruct)
sortFuncs.LenFunc = func() { return len(a) }
sortFuncs.LessFunc = func(i, j) { return a[i] < a[j] }
sortFuncs.SwapFunc = func(i, j) { temp = a[i]; a[i] = a[j]; a[j] = temp }
sort.Sort(sortFuncs)
fmt.Println(a)
`

	_, err := env.Execute(script)
	if err != nil {
		log.Fatalf("execute error: %v\n", err)
	}

}
Output:

[f 1.1 2 3 4.4 5]

Index

Examples

Constants

This section is empty.

Variables

View Source
var (

	// ErrBreak when there is an unexpected break statement
	ErrBreak = errors.New("unexpected break statement")
	// ErrContinue when there is an unexpected continue statement
	ErrContinue = errors.New("unexpected continue statement")
	// ErrReturn when there is an unexpected return statement
	ErrReturn = errors.New("unexpected return statement")
	// ErrInterrupt when execution has been interrupted
	ErrInterrupt = errors.New("execution interrupted")
)

Functions

func ClearInterrupt

func ClearInterrupt(env *Env)

ClearInterrupt removes the interrupt flag from specified environment. This includes all parent & child environments.

func Interrupt

func Interrupt(env *Env)

Interrupt interrupts the execution of any running statements in the specified environment. This includes all parent & child environments. Note that the execution is not instantly aborted: after a call to Interrupt, the current running statement will finish, but the next statement will not run, and instead will return a nilValue and an ErrInterrupt.

Example
package main

import (
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/mattn/anko/vm"
)

func main() {
	var waitGroup sync.WaitGroup
	waitGroup.Add(1)
	waitChan := make(chan struct{}, 1)

	env := vm.NewEnv()
	sleepMillisecond := func() { time.Sleep(time.Millisecond) }

	err := env.Define("println", fmt.Println)
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}
	err = env.Define("sleep", sleepMillisecond)
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}

	script := `
# sleep for 10 seconds
for i = 0; i < 10000; i++ {
	sleep()
}
# Should interrupt before printing the next line
println("this line should not be printed")
`

	go func() {
		close(waitChan)
		v, err := env.Execute(script)
		fmt.Println(v, err)
		waitGroup.Done()
	}()

	<-waitChan
	vm.Interrupt(env)

	waitGroup.Wait()

}
Output:

<nil> execution interrupted

func Run

func Run(stmts []ast.Stmt, env *Env) (interface{}, error)

Run executes statements in the specified environment.

func RunSingleStmt

func RunSingleStmt(stmt ast.Stmt, env *Env) (interface{}, error)

RunSingleStmt executes one statement in the specified environment.

func RunTest added in v0.0.4

func RunTest(t *testing.T, test Test, testingOptions *TestingOptions)

RunTest runs a VM test

func RunTests added in v0.0.4

func RunTests(t *testing.T, tests []Test, testingOptions *TestingOptions)

RunTests runs VM tests

func ValueEqual added in v0.0.4

func ValueEqual(v1 interface{}, v2 interface{}) bool

ValueEqual checks the values and returns true if equal If passed function, does extra checks otherwise just doing reflect.DeepEqual

Types

type Env

type Env struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Env provides interface to run VM. This mean function scope and blocked-scope. If stack goes to blocked-scope, it will make new Env.

func NewEnv

func NewEnv() *Env

NewEnv creates new global scope.

func NewPackage

func NewPackage(n string) *Env

NewPackage creates a new env with a name

func (*Env) AddPackage

func (e *Env) AddPackage(name string, methods map[string]interface{}, types map[string]interface{}) (*Env, error)

AddPackage creates a new env with a name that has methods and types in it. Created under the parent env

func (*Env) Addr

func (e *Env) Addr(k string) (reflect.Value, error)

Addr returns pointer value which specified symbol. It goes to upper scope until found or returns error.

func (*Env) Define

func (e *Env) Define(k string, v interface{}) error

Define defines symbol in current scope.

Example
package main

import (
	"fmt"
	"log"

	"github.com/mattn/anko/vm"
)

func main() {
	env := vm.NewEnv()
	env.SetName("myName")

	err := env.Define("println", fmt.Println)
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}

	err = env.Define("a", true)
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}
	err = env.Define("b", int64(1))
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}
	err = env.Define("c", float64(1.1))
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}
	err = env.Define("d", "d")
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}
	err = env.Define("e", []interface{}{true, int64(1), float64(1.1), "d"})
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}
	err = env.Define("f", map[string]interface{}{"a": true})
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}

	script := `
println(a)
println(b)
println(c)
println(d)
println(e)
println(f)
`

	_, err = env.Execute(script)
	if err != nil {
		log.Fatalf("execute error: %v\n", err)
	}

}
Output:

true
1
1.1
d
[true 1 1.1 d]
map[a:true]

func (*Env) DefineGlobal

func (e *Env) DefineGlobal(k string, v interface{}) error

DefineGlobal defines symbol in global scope.

func (*Env) DefineGlobalReflectType

func (e *Env) DefineGlobalReflectType(k string, t reflect.Type) error

DefineGlobalReflectType defines type in global scope.

func (*Env) DefineGlobalType

func (e *Env) DefineGlobalType(k string, t interface{}) error

DefineGlobalType defines type in global scope.

func (*Env) DefineReflectType

func (e *Env) DefineReflectType(k string, t reflect.Type) error

DefineReflectType defines type in current scope.

func (*Env) DefineType

func (e *Env) DefineType(k string, t interface{}) error

DefineType defines type in current scope.

func (*Env) Delete added in v0.0.4

func (e *Env) Delete(k string) error

Delete deletes symbol in current scope.

func (*Env) DeleteGlobal added in v0.0.4

func (e *Env) DeleteGlobal(k string) error

DeleteGlobal deletes the first matching symbol found in current or parent scope.

func (*Env) Destroy

func (e *Env) Destroy()

Destroy deletes current scope.

func (*Env) Dump

func (e *Env) Dump()

Dump show symbol values in the scope.

Example
package main

import (
	"log"

	"github.com/mattn/anko/vm"
)

func main() {
	env := vm.NewEnv()
	env.SetName("myName")

	err := env.Define("a", "a")
	if err != nil {
		log.Fatalf("Define error: %v\n", err)
	}

	_, err = env.Get("a")
	if err != nil {
		log.Fatalf("Get error: %v\n", err)
	}

	env.Dump()

}
Output:

Name: myName
Has parent: false
a = "a"

func (*Env) Execute

func (e *Env) Execute(src string) (interface{}, error)

Execute parses and runs source in current scope.

func (*Env) Get

func (e *Env) Get(k string) (interface{}, error)

Get returns value which specified symbol. It goes to upper scope until found or returns error.

func (*Env) GetName

func (e *Env) GetName() string

GetName returns module name.

func (*Env) NewEnv

func (e *Env) NewEnv() *Env

NewEnv creates new child scope.

func (*Env) NewModule

func (e *Env) NewModule(n string) *Env

NewModule creates new module scope as global.

func (*Env) NewPackage

func (e *Env) NewPackage(n string) *Env

NewPackage creates a new env with a name under the parent env

func (*Env) Set

func (e *Env) Set(k string, v interface{}) error

Set modifies value which specified as symbol. It goes to upper scope until found or returns error.

func (*Env) SetExternal

func (e *Env) SetExternal(res EnvResolver)

SetExternal sets an external resolver

func (*Env) SetName

func (e *Env) SetName(n string)

SetName sets a name of the scope. This means that the scope is module.

func (*Env) String

func (e *Env) String() string

String return the name of current scope.

func (*Env) Type

func (e *Env) Type(k string) (reflect.Type, error)

Type returns type which specified symbol. It goes to upper scope until found or returns error.

type EnvResolver

type EnvResolver interface {
	Get(string) (reflect.Value, error)
	Type(string) (reflect.Type, error)
}

EnvResolver provides an interface for extrenal values and types

type Error

type Error struct {
	Message string
	Pos     ast.Position
}

Error provides a convenient interface for handling runtime error. It can be Error interface with type cast which can call Pos().

func (*Error) Error

func (e *Error) Error() string

Error returns the error message.

type Test added in v0.0.4

type Test struct {
	Script         string
	ParseError     error
	ParseErrorFunc *func(*testing.T, error)
	EnvSetupFunc   *func(*testing.T, *Env)
	Types          map[string]interface{}
	Input          map[string]interface{}
	RunError       error
	RunErrorFunc   *func(*testing.T, error)
	RunOutput      interface{}
	Output         map[string]interface{}
}

Test is a struct use for testing VM

type TestingOptions added in v0.0.4

type TestingOptions struct {
	EnvSetupFunc *func(*testing.T, *Env)
}

TestingOptions are options to pass to RunTests or RunTest

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL