Kirsle.net logo Kirsle.net

RiveScript in Go

September 22, 2015 by Noah

Over the last couple months I've been slowly working on rewriting RiveScript in yet another programming language: Google's Go language! It's also my first project in Go, which is what tends to be the case (rewriting RiveScript in Java and Python were my first projects in those languages, too).

But this is the last time I'm going to be rewriting RiveScript from scratch.

With the recent release of Golang 1.5, a Go package can be compiled down to a C-compatible shared object file (like a .so or .dll, though I think they're still working on the DLL part). It means that modules written in Go can be linked from other programming languages, especially C or C++, but also to any programming language that can be extended with C. Which, as it turns out, is most of them.

For example, if I want to make RiveScript available to Ruby programmers, I can theoretically create a binding in Ruby for the Go version of RiveScript rather than rewrite RiveScript in Ruby.

The first language I'll probably do this to is Python, because I found a blog about writing Python modules in Go which will be pretty helpful. There's already a native RiveScript module for Python, but it will be a nice learning experience anyway. And who knows, it might even outperform the native Python version. ;)

Back to RiveScript-Go, a feature I think is interesting is that it natively supports JavaScript object macros via a library called otto, which implements a JavaScript interpreter natively in Go. The default rivescript.exe with my Go module already builds in the support for JavaScript objects. :)

Example implementation of the Go module:

package main

import (
    "bufio"
    "fmt"
    "strings"
    rivescript "github.com/aichaos/rivescript-go"
    "github.com/aichaos/rivescript-go/lang/rivescript_js"
)

func main() {
    // Initialize the bot.
    bot := rivescript.New()

    // JavaScript object macro handler.
    jsHandler := rivescript_js.New(bot)
    bot.SetHandler("javascript", jsHandler)
    
    // Golang functions work too, but must be compiled in.
    bot.SetSubroutine("gotest", func(rs *rivescript.RiveScript, args []string) string {
        return "Hello from Go!"
    })

    // Load a directory of RiveScript files.
    bot.LoadDirectory("./brain")

    bot.SortReplies()

    // Drop into the interactive command shell.
    reader := bufio.NewReader(os.Stdin)
    for {
        fmt.Print("You> ")
        text, _ := reader.ReadString('\n')
        text = strings.TrimSpace(text)
        if len(text) == 0 {
            continue
        }

        reply := bot.Reply("localuser", text)
        fmt.Printf("Bot> %s\n", reply)
    }
}

The JavaScript objects also get full access to the RiveScript object, so they can call methods like CurrentUser() and SetUservar().

Check it out on GitHub: https://github.com/aichaos/rivescript-go

Also, if I ever write a successor to RiveScript, I'll probably only implement it in Go or some other portable language rather than rewrite it five different times in five different languages. Rewriting something is a good way to learn a new language, but then it becomes pretty tedious maintaining them all. ;)

Tags:

Comments

There are 0 comments on this page. Add yours.

Add a Comment

Used for your Gravatar and optional thread subscription. Privacy policy.
You may format your message using GitHub Flavored Markdown syntax.