Last active
January 8, 2017 16:47
-
-
Save tenntenn/01cc64383d3c928ccaa25bf421f6d9dc to your computer and use it in GitHub Desktop.
もっと楽して式の評価器を作る #golang ref: http://qiita.com/tenntenn/items/590caa61b9701d2ada23
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (TypeAndValue, error) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pkg := types.NewPackage("main", "main") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mathPkg, err := importer.Default().Import("math") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pkg.SetImports([]*types.Package{ | |
mathPkg, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pkg.Scope().Insert(types.NewPkgName(token.NoPos, pkg, "math", mathPkg)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, "hoge", types.Typ[types.Float64], constant.MakeFloat64(100))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
>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