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
みんなのGo言語【現場で使える実践テクニック】
松木雅幸, mattn, 藤原俊一郎, 中島大一, 牧 大輔, 鈴木健太, 稲葉貴洋
技術評論社 大型本 / ¥351 (2016年09月09日)
発送可能時間:
松木雅幸, mattn, 藤原俊一郎, 中島大一, 牧 大輔, 鈴木健太, 稲葉貴洋
技術評論社 大型本 / ¥351 (2016年09月09日)
発送可能時間: