http://qiita.com/shuetsu@github/items/ac21e597265d6bb906dc
わりとよくある JSON ベースの lisp っぽいインタープリタの実装ですが、コードを見ていてもよくわからなかったので自分で実装しなおしてみました。
package main
import (
"encoding/json"
"fmt"
"log"
"os"
)
func eval(env map[string]interface{}, v interface{}) interface{} {
if vl, ok := v.([]interface{}); ok {
return doRun(env, vl)
}
return v
}
func doRun(env map[string]interface{}, v []interface{}) interface{} {
var r interface{}
mn := v[0].(string)
switch mn {
case "step":
for _, vi := range v[1:] {
r = doRun(env, vi.([]interface{}))
}
case "until":
for {
c := eval(env, v[1])
if c.(bool) == true {
break
}
r = doRun(env, v[2].([]interface{}))
}
case "get":
return env[eval(env, v[1]).(string)]
case "set":
env[eval(env, v[1]).(string)] = eval(env, v[2])
return v[2]
case "=":
return eval(env, v[1]).(float64) == eval(env, v[2]).(float64)
case "+":
return eval(env, v[1]).(float64) + eval(env, v[2]).(float64)
default:
panic("Unknown operation: " + fmt.Sprint(v))
}
return r
}
func main() {
source := `
["step",
["set", "i", 10],
["set", "sum", 0],
["until", ["=", ["get", "i"], 0], [
"step",
["set", "sum", ["+", ["get", "sum"], ["get", "i"]]],
["set", "i", ["+", ["get", "i"], -1]]
]],
["get", "sum"]
]`
var v interface{}
err := json.Unmarshal([]byte(source), &v)
if err != nil {
log.Fatal(err)
}
env := make(map[string]interface{})
defer func() {
err := recover()
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}()
fmt.Println(doRun(env, v.([]interface{})))
}
自分で書いた割に panic 前提なのが気に入らないし、そもそも orelang って同じ名前の言語持ってる。
GitHub - mattn/orelang: 俺言語
README.md orelang 俺言語 プログラミング言語の作り方 プログラミング言語の作り方(2) プログラミング言語の作り方(3) プログラミング言語の作り方(4) プログラミング言語の作り方...
http://github.com/mattn/orelang