Dune
Dune combines the simplicity, reliability and efficiency of Go with the flexibility of Typescript.
It is evolving so expect frequent breaking changes.
Install
Download a release or get it from source
go get github.com/dunelang/dune/cmd/dune
REPL:
Dune v0.95
> 1 + 2
3
Create a hello.ts:
fmt.println("Hello world")Run it:
$ dune hello.ts
Hello world
Examples
Arrays have multiple built in functions:
let items = [1, 2, 3, 4, 5]
let r = items.where(t => t > 2).select(t => t * t).sum()
console.log(r)A web server:
let s = http.newServer()
s.address = ":8080"
s.handler = (w, r) => w.write("Hello world")
s.start() Working with databases:
let db = sql.open("mysql", "test:123@unix(/var/run/mysqld/mysqld.sock)/")
db.exec("CREATE TABLE people (id KEY, name TEXT)")
db.exec("INSERT INTO people (name) VALUES (?)", "Bob")
for (let r of db.query("SELECT id, name FROM people")) {
console.log(r.id, r.name)
}Permissions
By default a virtual machine has no access to the external world. The file system is virtual.
This code throws: unauthorized
let p = bytecode.compileStr(`http.get("http://google.com")`)
let vm = runtime.newVM(p)
vm.run()Trusted machines are unrestricted:
vm.trusted = truePrograms can request permissions with directives:
// [permissions networking]
http.get("http://google.com") Execution limits:
This code throws: Step limit reached: 100
let p = bytecode.compileStr(`while(true) { }`)
let vm = runtime.newVM(p)
vm.maxSteps = 100
vm.run()This code throws: Max stack frames reached: 5
let p = bytecode.compileStr(`function main() { main() }`)
let vm = runtime.newVM(p)
vm.maxFrames = 5
vm.run()MaxAllocations counts the number of variables set and in the case of strings their size so it is not very useful yet. This code throws: Max allocations reached: 10
let p = bytecode.compileStr(`
let v = "*"
while(true) {
v += v
}
`)
let vm = runtime.newVM(p)
vm.maxAllocations = 10
vm.run()Checkout more examples.
Testing
Since everything is virtual, including the file system, programs are easily testable. There is an assert package in the standard library.
Writing programs
The syntax is a subset of Typescript to get type checking, autocompletion and refactoring tools from editors like VS Code.
$ dune --init
$ code rand.ts
Write a basic program:
export function main(len?: string) {
let n = convert.toInt(len || "15")
let v = crypto.randomAlphanumeric(n)
fmt.println(v)
} $ dune rand
1RyXuMFKwmxPbTa6bpXk
To decompile a program:
$ dune -d /tmp/rand.ts
=============================
Functions
=============================
0F @global
-----------------------------
0 return -- -- -- ; @global
1F main
-----------------------------
0 moveAndTest 2L 0L 3L ; /tmp/rand.ts:8
1 testJump 3L 1D 0D ; /tmp/rand.ts:8
2 move 2L 0K -- ; /tmp/rand.ts:8
3 callSingleArg 81N 1L 2L ; /tmp/rand.ts:8
4 callSingleArg 107N 4L 1L ; /tmp/rand.ts:9
5 callSingleArg 131N -- 4L ; /tmp/rand.ts:10
6 return -- -- -- ; /tmp/rand.ts:10
0L len 0-6
1L n 0-6
2L @ 0-6
3L @ 0-6
4L v 4-6
=============================
Constants
=============================
0K string 15
Embedding
package main
import (
"fmt"
"github.com/dunelang/dune"
)
func main() {
v, err := dune.RunStr("return 3 * 2")
fmt.Println(v, err)
}To call Go functions:
package main
import (
"fmt"
"log"
"github.com/dunelang/dune"
)
func main() {
dune.AddNativeFunc(dune.NativeFunction{
Name: "math.square",
Arguments: 1,
Function: func(this dune.Value, args []dune.Value, vm *dune.VM) (dune.Value, error) {
v := args[0].ToInt()
return dune.NewInt64(v * v), nil
},
})
p, err := dune.CompileStr("return math.square(5)")
if err != nil {
log.Fatal(err)
}
v, err := dune.NewVM(p).Run()
if err != nil {
log.Fatal(err)
}
fmt.Println(v)
}To import the standard library:
package main
import (
"log"
"github.com/dunelang/dune"
_ "github.com/dunelang/dune/lib"
)
func main() {
_, err := dune.RunStr(`
let v = { foo: 33 }
console.log(v)
`)
if err != nil {
log.Fatal(err)
}
}