Abstract
We have developed a complete Go interpreter for production use. We built this to bring you executable Go scripts, embedded dynamic Go plugins, interactive Go shells, and instant prototyping on top of the Go runtime.
Outline of the talk:•Motivation for a Go interpreter:••A plugin engine for traefik(ee), the cloud native edge router
••Contribute a missing piece to the Go ecosystem
•Project goal and priorities:
••An embeddable, production ready, standard Go interpreter
••Fully interoperable with the Go runtime
••Security, safety and robustness as first priorities
•Interpreter module API:
••i := interp.New()
••i.Use(stdlib)
••res, err := i.Eval(fmt.Println(“Hello”))
•Example: a scripted http server: http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Welcome to my website! ") }) http.ListenAndServe(":8080", nil)
•Status:
••< 8K LOC, no dependencies, alpha ready
••backed by Containo.us, the company behind traefik
••open source, Apache-2 license, feedback and contributions most welcome
••https://github.com/containous/yaegi
••https://containo.us
More detailed ContextWith its lightweight syntax, its type interface system, its well defined standard library, its powerful reflection scheme, the Go language itself could be extremely well suited to be used as a glue language embedded in applications, especially the ones written in Go.
Having the glue high level interpreted language being the same as the low level compiled one is advantageous on several levels: it relieves the burden of syntax switch, allows to move intensive code from interpreted to compiled mode with no rewrite, and puts no restriction on using all the features exposed by compiled modules, as the whole set of features, at language or library level, are made available for scripting.
But then, providing a useful interpreter is not only a matter of parsing and running the Go syntax in a sandbox, it’s about trading code and data back and forth between the dynamic interpreter context and the pre-compiled application. The classical use case is to provide pre-compiled packages for use in a script, but we perform also the opposite, exposing new objects and methods in script which can be invoked and consumed by the pre-compiled application.
The interpreter can run as a standalone command tool, either interactively in the terminal, or executing a script in a file. But, as a plugin engine and an extension language, it is used as a module in an application. The module API exposes mainly 3 functions: New() creates an interpreter context i, i.Eval(src), evaluates a string as Go statements and returns the result as a reflect.Value. i.Use(pkgs) makes an application set of compiled imports (such as stdlib) directly usable in the interpreter.
The above example (an http server sample) as a valid typical go code, can be compiled and run with go run. The exact same code runs out of the box within the interpreter. The trick is that the interpreted function which prints “Welcome…” is called on request by http.HandleFunc(), pre-compiled and part of go standard library. Other combinations are also possible: the callback could be defined in the application, not in the script, idem for the call to http.HandleFunc, which would be typically defined in the compiled part of a reverse proxy application like traefik. In that case the callback value would be the result of a previous i.Eval() call.