mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-06-27 21:39:22 +00:00
102
vendor/github.com/d5/tengo/script/compiled.go
generated
vendored
102
vendor/github.com/d5/tengo/script/compiled.go
generated
vendored
@ -3,6 +3,7 @@ package script
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/d5/tengo/compiler"
|
||||
"github.com/d5/tengo/objects"
|
||||
@ -12,26 +13,39 @@ import (
|
||||
// Compiled is a compiled instance of the user script.
|
||||
// Use Script.Compile() to create Compiled object.
|
||||
type Compiled struct {
|
||||
symbolTable *compiler.SymbolTable
|
||||
machine *runtime.VM
|
||||
globalIndexes map[string]int // global symbol name to index
|
||||
bytecode *compiler.Bytecode
|
||||
globals []objects.Object
|
||||
maxAllocs int64
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// Run executes the compiled script in the virtual machine.
|
||||
func (c *Compiled) Run() error {
|
||||
return c.machine.Run()
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
v := runtime.NewVM(c.bytecode, c.globals, c.maxAllocs)
|
||||
|
||||
return v.Run()
|
||||
}
|
||||
|
||||
// RunContext is like Run but includes a context.
|
||||
func (c *Compiled) RunContext(ctx context.Context) (err error) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
v := runtime.NewVM(c.bytecode, c.globals, c.maxAllocs)
|
||||
|
||||
ch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
ch <- c.machine.Run()
|
||||
ch <- v.Run()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
c.machine.Abort()
|
||||
v.Abort()
|
||||
<-ch
|
||||
err = ctx.Err()
|
||||
case err = <-ch:
|
||||
@ -40,30 +54,58 @@ func (c *Compiled) RunContext(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Clone creates a new copy of Compiled.
|
||||
// Cloned copies are safe for concurrent use by multiple goroutines.
|
||||
func (c *Compiled) Clone() *Compiled {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
clone := &Compiled{
|
||||
globalIndexes: c.globalIndexes,
|
||||
bytecode: c.bytecode,
|
||||
globals: make([]objects.Object, len(c.globals)),
|
||||
maxAllocs: c.maxAllocs,
|
||||
}
|
||||
|
||||
// copy global objects
|
||||
for idx, g := range c.globals {
|
||||
if g != nil {
|
||||
clone.globals[idx] = g
|
||||
}
|
||||
}
|
||||
|
||||
return clone
|
||||
}
|
||||
|
||||
// IsDefined returns true if the variable name is defined (has value) before or after the execution.
|
||||
func (c *Compiled) IsDefined(name string) bool {
|
||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
idx, ok := c.globalIndexes[name]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
v := c.machine.Globals()[symbol.Index]
|
||||
v := c.globals[idx]
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return *v != objects.UndefinedValue
|
||||
return v != objects.UndefinedValue
|
||||
}
|
||||
|
||||
// Get returns a variable identified by the name.
|
||||
func (c *Compiled) Get(name string) *Variable {
|
||||
value := &objects.UndefinedValue
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
||||
if ok && symbol.Scope == compiler.ScopeGlobal {
|
||||
value = c.machine.Globals()[symbol.Index]
|
||||
value := objects.UndefinedValue
|
||||
|
||||
if idx, ok := c.globalIndexes[name]; ok {
|
||||
value = c.globals[idx]
|
||||
if value == nil {
|
||||
value = &objects.UndefinedValue
|
||||
value = objects.UndefinedValue
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,20 +117,21 @@ func (c *Compiled) Get(name string) *Variable {
|
||||
|
||||
// GetAll returns all the variables that are defined by the compiled script.
|
||||
func (c *Compiled) GetAll() []*Variable {
|
||||
var vars []*Variable
|
||||
for _, name := range c.symbolTable.Names() {
|
||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
||||
if ok && symbol.Scope == compiler.ScopeGlobal {
|
||||
value := c.machine.Globals()[symbol.Index]
|
||||
if value == nil {
|
||||
value = &objects.UndefinedValue
|
||||
}
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
vars = append(vars, &Variable{
|
||||
name: name,
|
||||
value: value,
|
||||
})
|
||||
var vars []*Variable
|
||||
|
||||
for name, idx := range c.globalIndexes {
|
||||
value := c.globals[idx]
|
||||
if value == nil {
|
||||
value = objects.UndefinedValue
|
||||
}
|
||||
|
||||
vars = append(vars, &Variable{
|
||||
name: name,
|
||||
value: value,
|
||||
})
|
||||
}
|
||||
|
||||
return vars
|
||||
@ -97,17 +140,20 @@ func (c *Compiled) GetAll() []*Variable {
|
||||
// Set replaces the value of a global variable identified by the name.
|
||||
// An error will be returned if the name was not defined during compilation.
|
||||
func (c *Compiled) Set(name string, value interface{}) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
obj, err := objects.FromInterface(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
||||
if !ok || symbol.Scope != compiler.ScopeGlobal {
|
||||
idx, ok := c.globalIndexes[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("'%s' is not defined", name)
|
||||
}
|
||||
|
||||
c.machine.Globals()[symbol.Index] = &obj
|
||||
c.globals[idx] = obj
|
||||
|
||||
return nil
|
||||
}
|
||||
|
33
vendor/github.com/d5/tengo/script/conversion.go
generated
vendored
33
vendor/github.com/d5/tengo/script/conversion.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
package script
|
||||
|
||||
import (
|
||||
"github.com/d5/tengo/objects"
|
||||
)
|
||||
|
||||
func objectToInterface(o objects.Object) interface{} {
|
||||
switch val := o.(type) {
|
||||
case *objects.Array:
|
||||
return val.Value
|
||||
case *objects.Map:
|
||||
return val.Value
|
||||
case *objects.Int:
|
||||
return val.Value
|
||||
case *objects.Float:
|
||||
return val.Value
|
||||
case *objects.Bool:
|
||||
if val == objects.TrueValue {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
case *objects.Char:
|
||||
return val.Value
|
||||
case *objects.String:
|
||||
return val.Value
|
||||
case *objects.Bytes:
|
||||
return val.Value
|
||||
case *objects.Undefined:
|
||||
return nil
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
127
vendor/github.com/d5/tengo/script/script.go
generated
vendored
127
vendor/github.com/d5/tengo/script/script.go
generated
vendored
@ -14,17 +14,20 @@ import (
|
||||
// Script can simplify compilation and execution of embedded scripts.
|
||||
type Script struct {
|
||||
variables map[string]*Variable
|
||||
builtinFuncs []objects.Object
|
||||
builtinModules map[string]*objects.Object
|
||||
userModuleLoader compiler.ModuleLoader
|
||||
modules *objects.ModuleMap
|
||||
input []byte
|
||||
maxAllocs int64
|
||||
maxConstObjects int
|
||||
enableFileImport bool
|
||||
}
|
||||
|
||||
// New creates a Script instance with an input script.
|
||||
func New(input []byte) *Script {
|
||||
return &Script{
|
||||
variables: make(map[string]*Variable),
|
||||
input: input,
|
||||
variables: make(map[string]*Variable),
|
||||
input: input,
|
||||
maxAllocs: -1,
|
||||
maxConstObjects: -1,
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +40,7 @@ func (s *Script) Add(name string, value interface{}) error {
|
||||
|
||||
s.variables[name] = &Variable{
|
||||
name: name,
|
||||
value: &obj,
|
||||
value: obj,
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -55,38 +58,31 @@ func (s *Script) Remove(name string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// SetBuiltinFunctions allows to define builtin functions.
|
||||
func (s *Script) SetBuiltinFunctions(funcs []*objects.BuiltinFunction) {
|
||||
if funcs != nil {
|
||||
s.builtinFuncs = make([]objects.Object, len(funcs))
|
||||
for idx, fn := range funcs {
|
||||
s.builtinFuncs[idx] = fn
|
||||
}
|
||||
} else {
|
||||
s.builtinFuncs = []objects.Object{}
|
||||
}
|
||||
// SetImports sets import modules.
|
||||
func (s *Script) SetImports(modules *objects.ModuleMap) {
|
||||
s.modules = modules
|
||||
}
|
||||
|
||||
// SetBuiltinModules allows to define builtin modules.
|
||||
func (s *Script) SetBuiltinModules(modules map[string]*objects.ImmutableMap) {
|
||||
if modules != nil {
|
||||
s.builtinModules = make(map[string]*objects.Object, len(modules))
|
||||
for k, mod := range modules {
|
||||
s.builtinModules[k] = objectPtr(mod)
|
||||
}
|
||||
} else {
|
||||
s.builtinModules = map[string]*objects.Object{}
|
||||
}
|
||||
// SetMaxAllocs sets the maximum number of objects allocations during the run time.
|
||||
// Compiled script will return runtime.ErrObjectAllocLimit error if it exceeds this limit.
|
||||
func (s *Script) SetMaxAllocs(n int64) {
|
||||
s.maxAllocs = n
|
||||
}
|
||||
|
||||
// SetUserModuleLoader sets the user module loader for the compiler.
|
||||
func (s *Script) SetUserModuleLoader(loader compiler.ModuleLoader) {
|
||||
s.userModuleLoader = loader
|
||||
// SetMaxConstObjects sets the maximum number of objects in the compiled constants.
|
||||
func (s *Script) SetMaxConstObjects(n int) {
|
||||
s.maxConstObjects = n
|
||||
}
|
||||
|
||||
// EnableFileImport enables or disables module loading from local files.
|
||||
// Local file modules are disabled by default.
|
||||
func (s *Script) EnableFileImport(enable bool) {
|
||||
s.enableFileImport = enable
|
||||
}
|
||||
|
||||
// Compile compiles the script with all the defined variables, and, returns Compiled object.
|
||||
func (s *Script) Compile() (*Compiled, error) {
|
||||
symbolTable, builtinModules, globals, err := s.prepCompile()
|
||||
symbolTable, globals, err := s.prepCompile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -100,19 +96,41 @@ func (s *Script) Compile() (*Compiled, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := compiler.NewCompiler(srcFile, symbolTable, nil, builtinModules, nil)
|
||||
|
||||
if s.userModuleLoader != nil {
|
||||
c.SetModuleLoader(s.userModuleLoader)
|
||||
}
|
||||
|
||||
c := compiler.NewCompiler(srcFile, symbolTable, nil, s.modules, nil)
|
||||
c.EnableFileImport(s.enableFileImport)
|
||||
if err := c.Compile(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// reduce globals size
|
||||
globals = globals[:symbolTable.MaxSymbols()+1]
|
||||
|
||||
// global symbol names to indexes
|
||||
globalIndexes := make(map[string]int, len(globals))
|
||||
for _, name := range symbolTable.Names() {
|
||||
symbol, _, _ := symbolTable.Resolve(name)
|
||||
if symbol.Scope == compiler.ScopeGlobal {
|
||||
globalIndexes[name] = symbol.Index
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicates from constants
|
||||
bytecode := c.Bytecode()
|
||||
bytecode.RemoveDuplicates()
|
||||
|
||||
// check the constant objects limit
|
||||
if s.maxConstObjects >= 0 {
|
||||
cnt := bytecode.CountObjects()
|
||||
if cnt > s.maxConstObjects {
|
||||
return nil, fmt.Errorf("exceeding constant objects limit: %d", cnt)
|
||||
}
|
||||
}
|
||||
|
||||
return &Compiled{
|
||||
symbolTable: symbolTable,
|
||||
machine: runtime.NewVM(c.Bytecode(), globals, s.builtinFuncs, s.builtinModules),
|
||||
globalIndexes: globalIndexes,
|
||||
bytecode: bytecode,
|
||||
globals: globals,
|
||||
maxAllocs: s.maxAllocs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -141,39 +159,18 @@ func (s *Script) RunContext(ctx context.Context) (compiled *Compiled, err error)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Script) prepCompile() (symbolTable *compiler.SymbolTable, builtinModules map[string]bool, globals []*objects.Object, err error) {
|
||||
func (s *Script) prepCompile() (symbolTable *compiler.SymbolTable, globals []objects.Object, err error) {
|
||||
var names []string
|
||||
for name := range s.variables {
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
symbolTable = compiler.NewSymbolTable()
|
||||
|
||||
if s.builtinFuncs == nil {
|
||||
s.builtinFuncs = make([]objects.Object, len(objects.Builtins))
|
||||
for idx, fn := range objects.Builtins {
|
||||
s.builtinFuncs[idx] = &objects.BuiltinFunction{
|
||||
Name: fn.Name,
|
||||
Value: fn.Value,
|
||||
}
|
||||
}
|
||||
for idx, fn := range objects.Builtins {
|
||||
symbolTable.DefineBuiltin(idx, fn.Name)
|
||||
}
|
||||
|
||||
if s.builtinModules == nil {
|
||||
s.builtinModules = make(map[string]*objects.Object)
|
||||
}
|
||||
|
||||
for idx, fn := range s.builtinFuncs {
|
||||
f := fn.(*objects.BuiltinFunction)
|
||||
symbolTable.DefineBuiltin(idx, f.Name)
|
||||
}
|
||||
|
||||
builtinModules = make(map[string]bool)
|
||||
for name := range s.builtinModules {
|
||||
builtinModules[name] = true
|
||||
}
|
||||
|
||||
globals = make([]*objects.Object, runtime.GlobalsSize, runtime.GlobalsSize)
|
||||
globals = make([]objects.Object, runtime.GlobalsSize)
|
||||
|
||||
for idx, name := range names {
|
||||
symbol := symbolTable.Define(name)
|
||||
@ -195,7 +192,3 @@ func (s *Script) copyVariables() map[string]*Variable {
|
||||
|
||||
return vars
|
||||
}
|
||||
|
||||
func objectPtr(o objects.Object) *objects.Object {
|
||||
return &o
|
||||
}
|
||||
|
36
vendor/github.com/d5/tengo/script/variable.go
generated
vendored
36
vendor/github.com/d5/tengo/script/variable.go
generated
vendored
@ -9,7 +9,7 @@ import (
|
||||
// Variable is a user-defined variable for the script.
|
||||
type Variable struct {
|
||||
name string
|
||||
value *objects.Object
|
||||
value objects.Object
|
||||
}
|
||||
|
||||
// NewVariable creates a Variable.
|
||||
@ -21,7 +21,7 @@ func NewVariable(name string, value interface{}) (*Variable, error) {
|
||||
|
||||
return &Variable{
|
||||
name: name,
|
||||
value: &obj,
|
||||
value: obj,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -32,18 +32,18 @@ func (v *Variable) Name() string {
|
||||
|
||||
// Value returns an empty interface of the variable value.
|
||||
func (v *Variable) Value() interface{} {
|
||||
return objectToInterface(*v.value)
|
||||
return objects.ToInterface(v.value)
|
||||
}
|
||||
|
||||
// ValueType returns the name of the value type.
|
||||
func (v *Variable) ValueType() string {
|
||||
return (*v.value).TypeName()
|
||||
return v.value.TypeName()
|
||||
}
|
||||
|
||||
// Int returns int value of the variable value.
|
||||
// It returns 0 if the value is not convertible to int.
|
||||
func (v *Variable) Int() int {
|
||||
c, _ := objects.ToInt(*v.value)
|
||||
c, _ := objects.ToInt(v.value)
|
||||
|
||||
return c
|
||||
}
|
||||
@ -51,7 +51,7 @@ func (v *Variable) Int() int {
|
||||
// Int64 returns int64 value of the variable value.
|
||||
// It returns 0 if the value is not convertible to int64.
|
||||
func (v *Variable) Int64() int64 {
|
||||
c, _ := objects.ToInt64(*v.value)
|
||||
c, _ := objects.ToInt64(v.value)
|
||||
|
||||
return c
|
||||
}
|
||||
@ -59,7 +59,7 @@ func (v *Variable) Int64() int64 {
|
||||
// Float returns float64 value of the variable value.
|
||||
// It returns 0.0 if the value is not convertible to float64.
|
||||
func (v *Variable) Float() float64 {
|
||||
c, _ := objects.ToFloat64(*v.value)
|
||||
c, _ := objects.ToFloat64(v.value)
|
||||
|
||||
return c
|
||||
}
|
||||
@ -67,7 +67,7 @@ func (v *Variable) Float() float64 {
|
||||
// Char returns rune value of the variable value.
|
||||
// It returns 0 if the value is not convertible to rune.
|
||||
func (v *Variable) Char() rune {
|
||||
c, _ := objects.ToRune(*v.value)
|
||||
c, _ := objects.ToRune(v.value)
|
||||
|
||||
return c
|
||||
}
|
||||
@ -75,7 +75,7 @@ func (v *Variable) Char() rune {
|
||||
// Bool returns bool value of the variable value.
|
||||
// It returns 0 if the value is not convertible to bool.
|
||||
func (v *Variable) Bool() bool {
|
||||
c, _ := objects.ToBool(*v.value)
|
||||
c, _ := objects.ToBool(v.value)
|
||||
|
||||
return c
|
||||
}
|
||||
@ -83,11 +83,11 @@ func (v *Variable) Bool() bool {
|
||||
// Array returns []interface value of the variable value.
|
||||
// It returns 0 if the value is not convertible to []interface.
|
||||
func (v *Variable) Array() []interface{} {
|
||||
switch val := (*v.value).(type) {
|
||||
switch val := v.value.(type) {
|
||||
case *objects.Array:
|
||||
var arr []interface{}
|
||||
for _, e := range val.Value {
|
||||
arr = append(arr, objectToInterface(e))
|
||||
arr = append(arr, objects.ToInterface(e))
|
||||
}
|
||||
return arr
|
||||
}
|
||||
@ -98,11 +98,11 @@ func (v *Variable) Array() []interface{} {
|
||||
// Map returns map[string]interface{} value of the variable value.
|
||||
// It returns 0 if the value is not convertible to map[string]interface{}.
|
||||
func (v *Variable) Map() map[string]interface{} {
|
||||
switch val := (*v.value).(type) {
|
||||
switch val := v.value.(type) {
|
||||
case *objects.Map:
|
||||
kv := make(map[string]interface{})
|
||||
for mk, mv := range val.Value {
|
||||
kv[mk] = objectToInterface(mv)
|
||||
kv[mk] = objects.ToInterface(mv)
|
||||
}
|
||||
return kv
|
||||
}
|
||||
@ -113,7 +113,7 @@ func (v *Variable) Map() map[string]interface{} {
|
||||
// String returns string value of the variable value.
|
||||
// It returns 0 if the value is not convertible to string.
|
||||
func (v *Variable) String() string {
|
||||
c, _ := objects.ToString(*v.value)
|
||||
c, _ := objects.ToString(v.value)
|
||||
|
||||
return c
|
||||
}
|
||||
@ -121,7 +121,7 @@ func (v *Variable) String() string {
|
||||
// Bytes returns a byte slice of the variable value.
|
||||
// It returns nil if the value is not convertible to byte slice.
|
||||
func (v *Variable) Bytes() []byte {
|
||||
c, _ := objects.ToByteSlice(*v.value)
|
||||
c, _ := objects.ToByteSlice(v.value)
|
||||
|
||||
return c
|
||||
}
|
||||
@ -129,7 +129,7 @@ func (v *Variable) Bytes() []byte {
|
||||
// Error returns an error if the underlying value is error object.
|
||||
// If not, this returns nil.
|
||||
func (v *Variable) Error() error {
|
||||
err, ok := (*v.value).(*objects.Error)
|
||||
err, ok := v.value.(*objects.Error)
|
||||
if ok {
|
||||
return errors.New(err.String())
|
||||
}
|
||||
@ -140,10 +140,10 @@ func (v *Variable) Error() error {
|
||||
// Object returns an underlying Object of the variable value.
|
||||
// Note that returned Object is a copy of an actual Object used in the script.
|
||||
func (v *Variable) Object() objects.Object {
|
||||
return *v.value
|
||||
return v.value
|
||||
}
|
||||
|
||||
// IsUndefined returns true if the underlying value is undefined.
|
||||
func (v *Variable) IsUndefined() bool {
|
||||
return *v.value == objects.UndefinedValue
|
||||
return v.value == objects.UndefinedValue
|
||||
}
|
||||
|
Reference in New Issue
Block a user