Skip to content

Instantly share code, notes, and snippets.

@tenntenn
Last active January 8, 2017 16:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tenntenn/01cc64383d3c928ccaa25bf421f6d9dc to your computer and use it in GitHub Desktop.
Save tenntenn/01cc64383d3c928ccaa25bf421f6d9dc to your computer and use it in GitHub Desktop.
もっと楽して式の評価器を作る #golang ref: http://qiita.com/tenntenn/items/590caa61b9701d2ada23
func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (TypeAndValue, error)
package main
import (
"fmt"
"go/token"
"go/types"
"log"
)
func eval(expr string) (types.TypeAndValue, error) {
return types.Eval(token.NewFileSet(), types.NewPackage("main", "main"), token.NoPos, expr)
}
func main() {
tv, err := eval(`(100 + 1) * len("hoge")`)
if err != nil {
log.Fatal(err)
}
fmt.Println(tv.Value)
}
pkg := types.NewPackage("main", "main")
mathPkg, err := importer.Default().Import("math")
pkg.SetImports([]*types.Package{
mathPkg,
})
pkg.Scope().Insert(types.NewPkgName(token.NoPos, pkg, "math", mathPkg))
pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, "hoge", types.Typ[types.Float64], constant.MakeFloat64(100)))
package main
import (
"fmt"
"go/constant"
"go/importer"
"go/token"
"go/types"
"log"
)
func eval(expr string) (types.TypeAndValue, error) {
pkg := types.NewPackage("main", "main")
mathPkg, err := importer.Default().Import("math")
if err != nil {
return types.TypeAndValue{}, err
}
pkg.SetImports([]*types.Package{
mathPkg,
})
pkg.Scope().Insert(types.NewPkgName(token.NoPos, pkg, "math", mathPkg))
pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, "hoge", types.Typ[types.Float64], constant.MakeFloat64(100)))
return types.Eval(token.NewFileSet(), pkg, token.NoPos, expr)
}
func main() {
tv, err := eval(`(hoge + 1) * math.Pi`)
if err != nil {
log.Fatal(err)
}
fmt.Println(tv.Value)
}
package main
import (
"bufio"
"errors"
"fmt"
"go/token"
"go/types"
"os"
)
type Evaluator struct {
pkg *types.Package
fset *token.FileSet
outputCount int
}
func NewEvaluator() *Evaluator {
return &Evaluator{
pkg: types.NewPackage("main", "main"),
fset: token.NewFileSet(),
}
}
func (e *Evaluator) Count() int {
return e.outputCount
}
func (e *Evaluator) Eval(expr string) (string, error) {
pos := e.pkg.Scope().End()
tv, err := types.Eval(e.fset, e.pkg, pos, expr)
if err != nil {
return "", err
}
if tv.Type == nil || tv.Value == nil {
return "", errors.New("cannot eval expr")
}
e.outputCount++
outputName := fmt.Sprintf("o%d", e.outputCount)
e.pkg.Scope().Insert(types.NewConst(pos, e.pkg, outputName, tv.Type, tv.Value))
return tv.Value.ExactString(), nil
}
func main() {
e := NewEvaluator()
s := bufio.NewScanner(os.Stdin)
for {
fmt.Print(">")
if !s.Scan() {
break
}
expr := s.Text()
if expr == "bye" {
break
}
o, err := e.Eval(expr)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("[o%d]=%s", e.Count(), o)
fmt.Println()
}
}
if err := s.Err(); err != nil {
fmt.Println("Error:", err)
}
}
>1 + 1
[o1]=2
>o1 / 3
[o2]=0
>o1 / 3.0
[o3]=2/3
>o3 * (3 + 2i)
[o4]=(2 + 4/3i)
>bye
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment