Interpreter now exports itself, so scripts can do Eval() too

This commit is contained in:
Marc Vertes
2018-12-11 10:29:43 -08:00
parent 480ef53daf
commit b0ef0a00db
9 changed files with 469 additions and 460 deletions

View File

@@ -14,8 +14,8 @@ do
END {
print "func Example_'${file%.*}'() {"
print "src := `" src "`"
print "i := NewInterpreter(Opt{Entry: \"main\"}, \"'$file'\")"
print "i.Import(stdlib.Value, stdlib.Type)"
print "i := New(Opt{Entry: \"main\"})"
print "i.Use(stdlib.Value, stdlib.Type)"
print "i.Eval(src)"
print out
print "}"

13
_test/interp.gi Normal file
View File

@@ -0,0 +1,13 @@
package main
import (
"github.com/containous/dyngo/interp"
)
func main() {
i := interp.New(interp.Opt{})
i.Eval(`println("Hello")`)
}
// Output:
// Hello

View File

@@ -38,12 +38,14 @@ func main() {
// Allow executable go scripts, but fix them prior to parse
s = strings.Replace(s, "#!", "//", 1)
}
i := interp.NewInterpreter(opt, args[0])
i.Import(stdlib.Value, stdlib.Type)
i := interp.New(opt)
i.Use(stdlib.Value, stdlib.Type)
i.Use(interp.ExportValue, interp.ExportType)
i.Eval(string(s))
} else {
i := interp.NewInterpreter(opt, "")
i.Import(stdlib.Value, stdlib.Type)
i := interp.New(opt)
i.Use(stdlib.Value, stdlib.Type)
i.Use(interp.ExportValue, interp.ExportType)
s := bufio.NewScanner(os.Stdin)
prompt := getPrompt()
prompt()
@@ -56,46 +58,8 @@ func main() {
prompt()
}
}
/*
// To run test/plugin1.go or test/plugin2.go
p := &Plugin{"sample", "Middleware", 0, nil}
//p.Syms = i.Exports[p.Pkgname]
//ns := (*i.Expval[p.Pkgname])["NewSample"]
ns := i.Export("sample", "NewSample")
log.Println("ns:", ns)
rarg := []reflect.Value{reflect.ValueOf("test")}
res := ns.Call(rarg)
p.Id = int(res[0].Int())
p.handler = i.Export("sample", "WrapHandler").Interface().(func(int, http.ResponseWriter, *http.Request))
log.Println("res:", res, p.Id)
http.HandleFunc("/", p.Handler)
http.ListenAndServe(":8080", nil)
*/
/*
// To run test.plugin0.go
log.Println("frame:", i.Frame)
p := &Plugin{"sample", "Middleware", 0, nil}
p.Syms = i.Exports[p.Pkgname]
log.Println("p.Syms:", p.Syms)
http.HandleFunc("/", p.Handler)
http.ListenAndServe(":8080", nil)
*/
}
/*
// Plugin struct stores metadata for external modules
type Plugin struct {
Pkgname, Typename string
Id int
handler func(int, http.ResponseWriter, *http.Request)
}
// Handler redirect http.Handler processing in the interpreter
func (p *Plugin) Handler(w http.ResponseWriter, r *http.Request) {
p.handler(p.Id, w, r)
}
*/
// getPrompt returns a function which prints a prompt only if stdin is a terminal
func getPrompt() func() {
if stat, err := os.Stdin.Stat(); err == nil && stat.Mode()&os.ModeCharDevice != 0 {

View File

@@ -24,7 +24,7 @@ func main() {
log.SetFlags(log.Lshortfile)
//i := interp.NewInterpreter(interp.Opt{AstDot: true}, "")
i := interp.NewInterpreter(interp.Opt{}, "")
i.Import(stdlib.Value, stdlib.Type)
i.Use(stdlib.Value, stdlib.Type)
// Load plugin
_, err := i.Eval(`import "github.com/containous/dyngo/example/test_plugin/plugin"`)

Binary file not shown.

14
ii Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env dyngo
package main
import (
"github.com/containous/dyngo/interp"
)
func main() {
i := interp.New(interp.Opt{})
i.Eval(`println("Hello")`)
}
// Output:
// Hello

View File

@@ -78,6 +78,9 @@ func (interp *Interpreter) Gta(root *Node) {
ipath = n.child[0].val.(string)
name = path.Base(ipath)
}
if pkgName == "_" {
scope = interp.universe
}
if values, ok := interp.binValue[ipath]; ok {
if name == "." {
for n, v := range values {

View File

@@ -67,8 +67,24 @@ type Interpreter struct {
nindex int // next node index
universe *Scope // interpreter global level scope
scope map[string]*Scope // package level scopes, indexed by package name
binValue LibValueMap // imported binary values from runtime
binType LibTypeMap // imported binary types from runtime
binValue LibValueMap // runtime binary values used in interpreter
binType LibTypeMap // runtime binary types used in interpreter
}
var ExportValue = LibValueMap{}
var ExportType = LibTypeMap{}
func init() {
me := "github.com/containous/dyngo/interp"
ExportValue[me] = map[string]reflect.Value{
"New": reflect.ValueOf(New),
}
ExportType[me] = map[string]reflect.Type{
"Interpreter": reflect.TypeOf((*Interpreter)(nil)).Elem(),
"Opt": reflect.TypeOf((*Opt)(nil)).Elem(),
}
ExportValue[me]["ExportType"] = reflect.ValueOf(ExportType)
ExportValue[me]["ExportValue"] = reflect.ValueOf(ExportValue)
}
// Walk traverses AST n in depth first order, call cbin function
@@ -85,10 +101,9 @@ func (n *Node) Walk(in func(n *Node) bool, out func(n *Node)) {
}
}
// NewInterpreter creates and returns a new interpreter object
func NewInterpreter(opt Opt, name string) *Interpreter {
// New creates and returns a new interpreter object
func New(opt Opt) *Interpreter {
return &Interpreter{
Name: name,
Opt: opt,
universe: initUniverse(),
scope: map[string]*Scope{},
@@ -201,9 +216,9 @@ func (i *Interpreter) Eval(src string) (reflect.Value, error) {
return res, err
}
// Import loads binary runtime symbols in the interpreter context so
// Use loads binary runtime symbols in the interpreter context so
// they can be used in interpreted code
func (i *Interpreter) Import(values LibValueMap, types LibTypeMap) {
func (i *Interpreter) Use(values LibValueMap, types LibTypeMap) {
for k, v := range values {
i.binValue[k] = v
}

File diff suppressed because it is too large Load Diff