add script.Compiled.Set
function so compiled script can replace value of global variables
This commit is contained in:
parent
6420628310
commit
6a663c6360
3 changed files with 58 additions and 0 deletions
|
@ -80,6 +80,15 @@ func (v *VM) Abort() {
|
|||
|
||||
// Run starts the execution.
|
||||
func (v *VM) Run() error {
|
||||
// reset VM states
|
||||
v.sp = 0
|
||||
v.curFrame = &(v.frames[0])
|
||||
v.curInsts = v.curFrame.fn.Instructions
|
||||
v.curIPLimit = len(v.curInsts) - 1
|
||||
v.framesIndex = 1
|
||||
v.ip = -1
|
||||
atomic.StoreInt64(&v.aborting, 0)
|
||||
|
||||
for v.ip < v.curIPLimit && (atomic.LoadInt64(&v.aborting) == 0) {
|
||||
v.ip++
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package script
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/d5/tengo/compiler"
|
||||
"github.com/d5/tengo/objects"
|
||||
|
@ -92,3 +93,21 @@ func (c *Compiled) GetAll() []*Variable {
|
|||
|
||||
return vars
|
||||
}
|
||||
|
||||
// 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 {
|
||||
obj, err := objects.FromInterface(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
symbol, _, ok := c.symbolTable.Resolve(name)
|
||||
if !ok || symbol.Scope != compiler.ScopeGlobal {
|
||||
return fmt.Errorf("'%s' is not defined", name)
|
||||
}
|
||||
|
||||
c.machine.Globals()[symbol.Index] = &obj
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -47,6 +47,36 @@ func TestCompiled_IsDefined(t *testing.T) {
|
|||
compiledIsDefined(t, c, "b", false)
|
||||
}
|
||||
|
||||
func TestCompiled_Set(t *testing.T) {
|
||||
c := compile(t, `a := b`, M{"b": "foo"})
|
||||
compiledRun(t, c)
|
||||
compiledGet(t, c, "a", "foo")
|
||||
|
||||
// replace value of 'b'
|
||||
err := c.Set("b", "bar")
|
||||
assert.NoError(t, err)
|
||||
compiledRun(t, c)
|
||||
compiledGet(t, c, "a", "bar")
|
||||
|
||||
// try to replace undefined variable
|
||||
err = c.Set("c", 1984)
|
||||
assert.Error(t, err) // 'c' is not defined
|
||||
|
||||
// case #2
|
||||
c = compile(t, `
|
||||
a := func() {
|
||||
return func() {
|
||||
return b + 5
|
||||
}()
|
||||
}()`, M{"b": 5})
|
||||
compiledRun(t, c)
|
||||
compiledGet(t, c, "a", int64(10))
|
||||
err = c.Set("b", 10)
|
||||
assert.NoError(t, err)
|
||||
compiledRun(t, c)
|
||||
compiledGet(t, c, "a", int64(15))
|
||||
}
|
||||
|
||||
func TestCompiled_RunContext(t *testing.T) {
|
||||
// machine completes normally
|
||||
c := compile(t, `a := 5`, nil)
|
||||
|
|
Loading…
Reference in a new issue