Wrengo is binding for Wren scripting language.
The package has not been updated for a long time, based on 0.2.0 Wren, and not compiles on Go version bigger than 1.14
If anyone really needs updated package, open issue ^_^
package main
import (
"fmt"
"github.com/Terisback/wrengo"
)
func main() {
config := wrengo.NewConfiguration()
config.WriteFunc = wrengo.CallbackWrite
vm := wrengo.NewVM(config)
defer vm.FreeVM()
vm.Interpret("main", `System.print("Hello world!")`)
}
First of all, download and install Go. The project is written within 1.14
, but you can try your luck.
Installation is done using the go get
command:
go get -u github.com/Terisback/wrengo
Also you need installed gcc
:
On Windows you need Mingw-w64 or TDM-GCC. You can also build binary in MSYS2 shell.
On MacOS you need Xcode or Command Line Tools for Xcode.
- Wren is small. The VM implementation is under 4,000 semicolons. You can skim the whole thing in an afternoon. It’s small, but not dense. It is readable and lovingly-commented.
- Wren is fast. A fast single-pass compiler to tight bytecode, and a compact object representation help Wren compete with other dynamic languages.
- Wren is class-based. There are lots of scripting languages out there, but many have unusual or non-existent object models. Wren places classes front and center.
- Wren is concurrent. Lightweight fibers are core to the execution model and let you organize your program into an army of communicating coroutines.
fib(35) | fibt(35) | Type | |
---|---|---|---|
Go | 96ms |
25ms |
Go (native) |
Wrengo | 34ms |
29ms |
Wren VM |
Tengo | 34ms |
30ms |
VM on Go |
Lua | 2ms |
25ms |
Lua (native) |
go-lua | 7ms |
26ms |
Lua VM on Go |
GopherLua | 7ms |
29ms |
Lua VM on Go |
Python | 5ms |
58ms |
Python (native) |
starlark-go | 16ms |
26ms |
Python-like Interpreter on Go |
gpython | 49ms |
42ms |
Python Interpreter on Go |
goja | 8ms |
28ms |
JS VM on Go |
otto | 131ms |
35ms |
JS Interpreter on Go |
Anko | 126ms |
27ms |
Interpreter on Go |
* fib(35):
Fibonacci(35)
* fibt(35):
tail-call version of Fibonacci(35)
* Go does not read the source code from file, while all other cases do
* Results were rounded up
* Tested on my Microsoft Sufrace 6 Pro
* See here for commands/codes used
Foreign Function Limits Due to Go's inability to generate C-exported functions at runtime, the number of foreign methods able to be registered with the Wren VM through this package is limited
to 256 for functions and 256 for classes. This number is completely arbitrary, though, and can be changed by modifying
the directive at the bottom of wrengo.go and running "go generate". If you feel like
this number is a terrible default, pull requests will be happily accepted.
Cast types when receiving foreign class. I think there is a more “right” way to do this. Feel free to pull request.
Simplified examples is listed below. (Without error checking and import)
Full examples are stored in the cmd folder
func main() {
// New configuration for VM
config := wrengo.NewConfiguration()
// Adding callbacks
config.WriteFunc = wrengo.CallbackWrite
config.ErrorFunc = wrengo.CallbackError
// Creating new VM
vm := wrengo.NewVM(config)
defer vm.FreeVM()
// New console read buffer
reader := bufio.NewReader(os.Stdin)
fmt.Println("Ready! Press Ctrl+C for exit.")
// Interpret loop
for {
fmt.Print("> ")
text, _ := reader.ReadString('\n')
vm.Interpret("main", text+"\n")
}
}
func main() {
program := `
class WrenMath {
static do_add(a, b) {
return a + b
}
}
`
config := wrengo.NewConfiguration()
config.WriteFunc = wrengo.CallbackWrite
config.ErrorFunc = wrengo.CallbackError
vm := wrengo.NewVM(config)
defer vm.FreeVM()
vm.Interpret(wrengo.DefaultModule, program)
// Make sure enough slots are allocated
vm.EnsureSlots(3)
// Getting class to slot 0
vm.GetVariable(wrengo.DefaultModule, "WrenMath", 0)
// Creating handle to do_add function
h := vm.NewCallHandle("do_add(_,_)")
// Setting call arguments
vm.SetSlotDouble(1, 9)
vm.SetSlotDouble(2, 3)
// Calling
h.Call()
// Print the result
fmt.Println(vm.GetSlotDouble(0))
}
type God struct { msg string }
// The constructor for a foreign type takes no arguments and returns
// an interface{} value representing the new object.
func NewGod() interface{} {
return &God{msg: "What are you doing? %s"}
}
// Function to bind into Wren
func GetGodsMessage(vm *wrengo.VM) {
// Getting foreign class
god := vm.GetSlotForeign(0, God{}).(God)
// Getting argument
name := vm.GetSlotString(1)
// Return result
vm.SetSlotString(0, fmt.Sprintf(god.msg, name))
}
func main() {
// Wren code
program := `
foreign class God {
construct new() {}
foreign getMessage(name)
}
var god = God.new()
System.print(god.getMessage("Silly boy"))
`
config := wrengo.NewConfiguration()
config.WriteFunc = wrengo.CallbackWrite
config.ErrorFunc = wrengo.CallbackError
vm := wrengo.NewVM(config)
defer vm.FreeVM()
// Bind God class
vm.BindForeignClass("God", NewGod)
// Bind God.getMessage()
vm.BindForeignMethod("God", false, "getMessage(_)", GetGodsMessage)
vm.Interpret(wrengo.DefaultModule, program)
}
- go-wren - it's based on nearly 0.1.0 Wren sources, when Wrengo based on 0.2.0 Wren release. It's doing same work as this package, but working with older version of Wren and it has more simplifications.
- tengo - Tengo is fast and secure because it's compiled/executed as bytecode on stack-based VM that's written in native Go.
- go-lua - Port of the Lua 5.2 VM to pure Go.
More in awesome-go repository.