Simplify export to runtime

This commit is contained in:
Marc Vertes
2018-12-04 15:14:02 +01:00
parent e508591277
commit 6b013ffd35
6 changed files with 37 additions and 73 deletions

View File

@@ -12,11 +12,11 @@ type Sample struct{ Name string }
var samples = []Sample{}
func (s *Sample) Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Welcome to my website", s.Name)
fmt.Fprintln(w, "Welcome to my website", s.Name, version)
}
func NewSample(name string) int {
fmt.Println("in NewSample", version)
fmt.Println("in NewSample", name, version)
i := len(samples)
samples = append(samples, Sample{Name: name})
return i

View File

@@ -7,7 +7,6 @@ import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
@@ -50,20 +49,22 @@ func main() {
/*
// 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"]
//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 = res[0].Interface().(int)
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", i, nil}
p := &Plugin{"sample", "Middleware", 0, nil}
p.Syms = i.Exports[p.Pkgname]
log.Println("p.Syms:", p.Syms)
http.HandleFunc("/", p.Handler)
@@ -71,14 +72,16 @@ func main() {
*/
}
/*
// Plugin struct stores metadata for external modules
type Plugin struct {
Pkgname, Typename string
ID int
Syms *interp.BinMap
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.Syms)["WrapHandler"].(func(int, http.ResponseWriter, *http.Request))(p.ID, w, r)
p.handler(p.Id, w, r)
}
*/

View File

@@ -118,8 +118,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
scope := interp.universe
var loop, loopRestart *Node
var initNodes []*Node
var exports *BinMap
var expval *ValueMap
var iotaValue int
var pkgName string
@@ -179,15 +177,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
}
scope = interp.scope[pkgName]
scope.size = interp.fsize
if pkg, ok := interp.Exports[pkgName]; ok {
exports = pkg
expval = interp.Expval[pkgName]
} else {
exports = &BinMap{}
interp.Exports[pkgName] = exports
expval = &ValueMap{}
interp.Expval[pkgName] = expval
}
case For0, ForRangeStmt:
loop, loopRestart = n, n.child[0]
@@ -556,7 +545,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
case ForRangeStmt:
loop, loopRestart = nil, nil
n.start = n.child[0].start
//n.findex = n.child[0].findex
n.child[0].fnext = n
scope = scope.pop()
@@ -569,10 +557,6 @@ func (interp *Interpreter) Cfg(root *Node) []*Node {
n.framepos = append(n.framepos, n.child[2].framepos...)
scope = scope.pop()
funcName := n.child[1].ident
if canExport(funcName) {
(*exports)[funcName] = reflect.MakeFunc(n.child[2].typ.TypeOf(), n.wrapNode).Interface()
(*expval)[funcName] = reflect.MakeFunc(n.child[2].typ.TypeOf(), n.wrapNode)
}
n.typ = n.child[2].typ
n.val = n
n.start = n.child[3].start
@@ -1184,7 +1168,7 @@ func frameTypes(node *Node, size int) []reflect.Type {
node.Walk(func(n *Node) bool {
if n.kind == FuncDecl || n.kind == ImportDecl || n.kind == TypeDecl || n.kind == FuncLit {
return n == node // Do not dive in substree, except if this the entry point
return n == node // Do not dive in substree, except if this is the entry point
}
if n.findex < 0 || n.typ == nil || n.level > 0 || n.kind == BasicLit || n.kind == SelectorSrc || n.typ.cat == BinPkgT {
return true

View File

@@ -8,7 +8,7 @@ func Exported() { println("Hello from Exported") }
i := NewInterpreter(Opt{}, "export_test")
i.Eval(src)
f := (*i.Exports["tst"])["Exported"].(func())
f := i.Export("tst", "Exported").Interface().(func())
f()
// Output:

View File

@@ -1,6 +1,7 @@
package interp
import (
"log"
"reflect"
"github.com/containous/dyngo/stdlib"
@@ -81,8 +82,6 @@ type Interpreter struct {
scope map[string]*Scope // package level scopes, indexed by package name
binValue LibValueMap
binType LibTypeMap
Exports PkgMap // exported symbols for use by runtime
Expval PkgValueMap // same as abobe (TODO: keep only one)
}
// Walk traverses AST n in depth first order, call cbin function
@@ -106,8 +105,6 @@ func NewInterpreter(opt Opt, name string) *Interpreter {
Opt: opt,
universe: initUniverse(),
scope: map[string]*Scope{},
Exports: make(PkgMap),
Expval: make(PkgValueMap),
binValue: LibValueMap(stdlib.Value),
binType: LibTypeMap(stdlib.Type),
Frame: &Frame{data: []reflect.Value{}},
@@ -167,7 +164,8 @@ func (i *Interpreter) resizeFrame() {
// Eval evaluates Go code represented as a string. It returns a map on
// current interpreted package exported symbols
func (i *Interpreter) Eval(src string) string {
func (i *Interpreter) Eval(src string) error {
var err error
// Parse source to AST
pkgName, root := i.Ast(src, i.Name)
if i.AstDot {
@@ -198,5 +196,22 @@ func (i *Interpreter) Eval(src string) string {
i.run(n, i.Frame)
}
}
return root.child[0].ident
return err
}
// Export returns a value defined in the interpreter during execution
// for use in the runtime
func (i *Interpreter) Export(pkg, name string) reflect.Value {
sym := i.scope[pkg].sym[name]
var res reflect.Value
if sym == nil {
return res
}
switch sym.kind {
case Func:
log.Println("Export func", pkg+"."+name, sym.node.index)
wrapper := genNodeWrapper(sym.node)
res = wrapper(i.Frame)
}
return res
}

View File

@@ -274,44 +274,6 @@ func _panic(n *Node) {
}
}
// wrapNode wraps a call to an interpreter node in a function that can be called from runtime
// FIXME: wrapNode is now redundant with genNodeWrapper(). it should be removed.
func (n *Node) wrapNode(in []reflect.Value) []reflect.Value {
def := n.val.(*Node)
var result []reflect.Value
if n.frame == nil {
n.frame = n.interp.Frame
}
log.Println(n.index, "in wrapNode", def.index, n.frame)
frame := Frame{anc: n.frame, data: make([]reflect.Value, def.flen)}
// If fucnction is a method, set its receiver data in the frame
if len(def.child[0].child) > 0 {
//frame.data[def.child[0].findex] = n.recv.node.value(n.frame)
}
// Unwrap input arguments from their reflect value and store them in the frame
i := 0
for _, arg := range in {
frame.data[def.framepos[i]] = arg
i++
}
// Interpreter code execution
runCfg(def.child[3].start, &frame)
// Wrap output results in reflect values and return them
if len(def.child[2].child) > 1 {
if fieldList := def.child[2].child[1]; fieldList != nil {
result = make([]reflect.Value, len(fieldList.child))
for i := range fieldList.child {
result[i] = reflect.ValueOf(frame.data[i])
}
}
}
return result
}
func genNodeWrapper(n *Node) func(*Frame) reflect.Value {
def := n.val.(*Node)
setExec(def.child[3].start)