Interactive Go interpreter and debugger with REPL, Eval, generics and Lisp-like macros
Interactive Go interpreter and debugger with REPL, Eval, generics and Lisp-like macros
gomacro is an almost complete Go interpreter, implemented in pure Go. It offers both an interactive REPL and a scripting mode, and does not require a Go toolchain at runtime (except in one very specific case: import of a 3rd party package at runtime).
It has two dependencies beyond the Go standard library: github.com/peterh/liner and golang.org/x/tools/go/packages
Gomacro can be used as:
a standalone executable with interactive Go REPL, line editing and code completion:
just run gomacro from your command line, then type Go code. Example:
$ gomacro
[greeting message...]
gomacro> import "fmt"
gomacro> fmt.Println("hello, world!")
hello, world!
14 // int
<nil> // error
gomacro>
press TAB to autocomplete a word, and press it again to cycle on possible completions.
Line editing follows mostly Emacs: Ctrl+A or Home jumps to start of line, Ctrl+E or End jumps to end of line, Ald+D deletes word starting at cursor... For the full list of key bindings, see https://github.com/peterh/liner
a tool to experiment with Go generics: see Generics
a Go source code debugger: see Debugger
an interactive tool to make science more productive and more fun. If you use compiled Go with scientific libraries (physics, bioinformatics, statistics...) you can import the same libraries from gomacro REPL (immediate on Linux and Mac OS X, requires restarting on other platforms, see Importing packages below), call them interactively, inspect the results, feed them to other functions/libraries, all in a single session. The imported libraries will be compiled, not interpreted, so they will be as fast as in compiled Go.
For a graphical user interface on top of gomacro, see Gophernotes. It is a Go kernel for Jupyter notebooks and nteract, and uses gomacro for Go code evaluation.
a library that adds Eval() and scripting capabilities to your Go programs in few lines of code:
package main
import (
"fmt"
"reflect"
"github.com/cosmos72/gomacro/fast"
)
func RunGomacro(toeval string) reflect.Value {
interp := fast.New()
vals, _ := interp.Eval(toeval)
// for simplicity, only use the first returned value
return vals[0].ReflectValue()
}
func main() {
fmt.Println(RunGomacro("1+1"))
}
Also, github issue #13 explains how to have your application's functions, variable, constants and types available in the interpreter.
Note: gomacro license is MPL 2.0, which imposes some restrictions on programs that use gomacro. See MPL 2.0 FAQ for common questions regarding the license terms and conditions.
a way to execute Go source code on-the-fly without a Go compiler:
you can either run gomacro FILENAME.go (works on every supported platform)
or you can insert a line #!/usr/bin/env gomacro at the beginning of a Go source file,
then mark the file as executable with chmod +x FILENAME.go and finally execute it
with ./FILENAME.go (works only on Unix-like systems: Linux, *BSD, Mac OS X ...)
a Go code generation tool: gomacro was started as an experiment to add Lisp-like macros to Go, and they are extremely useful (in the author's opinion) to simplify code generation. Macros are normal Go functions, they are special only in one aspect: they are executed before compiling code, and their input and output is code (abstract syntax trees, in the form of go/ast.Node)
Don't confuse them with C preprocessor macros: in Lisp, Scheme and now in Go, macros are regular functions written in the same programming language as the rest of the source code. They can perform arbitrary computations and call any other function or library: they can even read and write files, open network connections, etc... as a normal Go function can do.
See doc/code_generation.pdf for an introduction to the topic.
Gomacro is pure Go, and in theory it should work on any platform supported by the Go compiler. The following combinations are tested and known to work:
The command
go install github.com/cosmos72/gomacro@latest
downloads, compiles and installs gomacro and its dependencies
Almost complete.
The main limitations and missing features are:
var a = b; var b = 42The documentation also contains the full list of features and limitations
Compared to compiled Go, gomacro supports several extensions:
an integrated debugger, see Debugger
configurable special commands. Type :help at REPL to list them,
and see cmd.go:37
for the documentation and API to define new ones.
untyped constants can be manipulated directly at REPL. Examples:
gomacro> 1<<100
{int 1267650600228229401496703205376} // untyped.Lit
gomacro> const c = 1<<100; c * c / 100000000000
{int 16069380442589902755419620923411626025222029937827} // untyped.Lit
This provides a handy arbitrary-precision calculator.
Note: operations on large untyped integer constants are always exact,
while operations on large untyped float constants are implemented with go/constant.Value,
and are exact as long as both numerator and denominator are <= 5e1232.
Beyond that, go/constant.Value switches from *big.Rat to *big.Float
with precision = 512, which can accumulate rounding errors.
If you need exact results, convert the untyped float constant to *big.Rat
(see next item) before exceeding 5e1232.
untyped constants can be converted implicitly to *big.Int, *big.Rat and *big.Float. Examples:
import "math/big"
var i *big.Int = 1<<1000 // exact - would overflow int
var r *big.Rat = 1.000000000000000000001 // exact - different from 1.0
var s *big.Rat = 5e1232 // exact - would overflow float64
var t *big.Rat = 1e1234 // approximate, exceeds 5e1232
var f *big.Float = 1e646456992 // largest untyped float constant that is different from +Inf
Note: every time such a conversion is evaluated, it creates a new value - no risk to modify the constant.
Be aware that converting a huge value to string, as typing f at REPL would do, can be very slow.
zero value constructors: for any type T, the expression T()
returns the zero value of the type
macros, quoting and quasiquoting: see doc/code_generation.pdf
and slightly relaxed checks:
Some short, notable examples - to run them on non-Linux platforms, see Importing packages first.
go get gonum.org/v1/plot gonum.org/v1/plot/plotter gonum.org/v1/plot/vggomacromain()
If all goes well, it will create a file named "functions.png" in current directory containing the plotted functions.go get github.com/sverrirab/mandelbrot-gocd; cd go/src/github.com/sverrirab/mandelbrot-gogomacro -i mbrot.goinit(); main()Further examples are listed by Gophernotes
Gomacro supports the standard Go syntax import, including package renaming. Examples:
import "fmt"
import (
"io"
"net/http"
r "reflect"
)
Third party packages - i.e. packages not in Go standard library - can also be imported with the same syntax.
Extension: unpublished packages can also be imported from a local filesystem directory (implemented on 2022-05-28). Supported syntaxes are:
import (
"." // imports the package in current directory
".." // imports the package in parent directory
"./some/relative/path" // "./" means relative to current directory
"../some/other/relative/path" // "../" means relative to parent directory
"/some/absolute/path" // "/" means absolute
)
For an import to work, you usually need to follow its installation procedure: sometimes there are additional prerequisites to install, and the typical command go get PACKAGE-PATH may or may not be needed.
The next steps depend on the system you are running gomacro on:
If you are running gomacro on Linux, Mac OS X or *BSD, import will then just work:
it will automatically download, compile and import a package. Example:
…
Note: internally, gomacro will compile and load a single Go plugin containing the exported declarations
of all the packages listed in import ( ... ).
The command go mod tidy is automatically executed before compiling the plugin, and it tries - among other things -
to resolve any version conflict due to different versions of the same package being imported directly
(i.e. listed in import ( ... )) or indirectly (i.e. as a required dependency).
Go plugins are currently supported only on Linux and Mac OS X.
WARNING On Mac OS X, never execu
No open issues yet, or sync has not completed.