As part of one of the projects we’ve been pushing at Canonical, I spent a few days researching about the possibility of extending a compiled Go application with a tiny language that would allow expressing simple procedural logic in a controlled environment. Although we’re not yet sure of the direction we’ll take, the result of this short experiment is being released as the twik language for open fiddling.

The implementation is straightforward, with under 400 lines for the parser and evaluator at the time of this writing, and under 350 lines in the default functions provided for the language skeleton: var, func, do, if, and, or, etc.

It also comes with an interactive interpreter to play with. You can install it with:

$ go get gopkg.in/twik.v1/cmd/twik

This is a short sample session:



> (var x 1) > x 1 > (set x 2) > x 2 > (set x (func (n) (+ n 1))) > x #func > (x 1) 2 > (func inc (n) (+ n 1)) #func > (inc 42) 43

Another one demonstrating the lexical scoping:

> (var add . (do . (var n 0) . (func (m) (set n (+ n m)) n) . ) . ) > (add 5) 5 > (add -1) 4 > n twik source:1:1: undefined symbol: n

New functionality may be plugged in by providing Go functions. For example, here is a simple printf function:

func printf(args []interface{}) (interface{}, error) { if len(args) > 0 { if format, ok := args[0].(string); ok { _, err := fmt.Printf(format, args[1:]...) return nil, err } } return nil, fmt.Errorf("printf takes a format string") } func main() { ... err = scope.Create("printf", printf) ... }

It can now greet the world:

$ cat test.twik (func hello (name) (printf "Hello %s!

" name) ) (hello "world") $ time ./twik test.twik Hello world! ./twik test.twik 0.00s user 0.00s system 74% cpu 0.005 total