x
x
x


Do so in a way which:

 does not involve string manipulation of the input source code
 is plausibly extensible to a runtime-chosen set of bindings rather than just x
 does not make x a global variable


or note that these are impossible.



See also

 For more general examples and language-specific details, see Eval.
 Dynamic variable names is a similar task.


package main
 
import (
    "bitbucket.org/binet/go-eval/pkg/eval"
    "fmt"
    "go/parser"
    "go/token"
)
 
func main() {
    // an expression on x
    squareExpr := "x*x"
 
    // parse to abstract syntax tree
    fset := token.NewFileSet()
    squareAst, err := parser.ParseExpr(squareExpr)
    if err != nil {
        fmt.Println(err)
        return
    }
    // create an environment or "world"
    w := eval.NewWorld()
 
    // allocate a variable
    wVar := new(intV)
 
    // bind the variable to the name x
    err = w.DefineVar("x", eval.IntType, wVar)
    if err != nil {
        fmt.Println(err)
        return
    }
    // bind the expression AST to the world
    squareCode, err := w.CompileExpr(fset, squareAst)
    if err != nil {
        fmt.Println(err)
        return
    }
    // directly manipulate value of variable within world
    *wVar = 5
    // evaluate
    r0, err := squareCode.Run()
    if err != nil {
        fmt.Println(err)
        return
    }
    // change value
    *wVar--
    // revaluate
    r1, err := squareCode.Run()
    if err != nil {
        fmt.Println(err)
        return
    }
    // print difference
    fmt.Println(r0.(eval.IntValue).Get(nil) - r1.(eval.IntValue).Get(nil))
}
 
// int value implementation.
type intV int64
 
func (v *intV) String() string              { return fmt.Sprint(*v) }
func (v *intV) Get(*eval.Thread) int64      { return int64(*v) }
func (v *intV) Set(_ *eval.Thread, x int64) { *v = intV(x) }
func (v *intV) Assign(t *eval.Thread, o eval.Value) {
    *v = intV(o.(eval.IntValue).Get(t))
}