diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-09 22:10:15 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-06 21:57:02 -0600 |
| commit | 1771ab50b87c745181e4e30f94b63e3f23d33dac (patch) | |
| tree | c1c9b5d80ba9261c5f16bab1b52c1bb0f559407c /go/src | |
| parent | f2544a9467ea032aff505b3ced3b4b3510a828fe (diff) | |
| download | mal-1771ab50b87c745181e4e30f94b63e3f23d33dac.tar.gz mal-1771ab50b87c745181e4e30f94b63e3f23d33dac.zip | |
go: update README. Backport Func usage.
Diffstat (limited to 'go/src')
| -rw-r--r-- | go/src/core/core.go | 33 | ||||
| -rw-r--r-- | go/src/step5_tco/step5_tco.go | 6 | ||||
| -rw-r--r-- | go/src/step6_file/step6_file.go | 15 | ||||
| -rw-r--r-- | go/src/step7_quote/step7_quote.go | 15 | ||||
| -rw-r--r-- | go/src/step8_macros/step8_macros.go | 17 | ||||
| -rw-r--r-- | go/src/stepA_more/stepA_more.go | 19 | ||||
| -rw-r--r-- | go/src/types/types.go | 29 |
7 files changed, 102 insertions, 32 deletions
diff --git a/go/src/core/core.go b/go/src/core/core.go index f5d5842..57cf932 100644 --- a/go/src/core/core.go +++ b/go/src/core/core.go @@ -195,6 +195,34 @@ func do_map(a []MalType) (MalType, error) { return List{results,nil}, nil } +func conj(a []MalType) (MalType, error) { + if len(a) <2 { return nil, errors.New("conj requires at least 2 arguments") } + switch seq := a[0].(type) { + case List: + new_slc := []MalType{} + for i := len(a)-1 ; i > 0 ; i-=1 { + new_slc = append(new_slc, a[i]) + } + return List{append(new_slc, seq.Val...),nil}, nil + case Vector: + new_slc := seq.Val + for _, x := range a[1:] { + new_slc = append(new_slc, x) + } + return Vector{new_slc,nil}, nil + } + + if !HashMap_Q(a[0]) { return nil, errors.New("dissoc called on non-hash map") } + new_hm := copy_hash_map(a[0].(HashMap)) + for i := 1; i < len(a); i+=1 { + key := a[i] + if !String_Q(key) { return nil, errors.New("dissoc called with non-string key") } + delete(new_hm.Val,key.(string)) + } + return new_hm, nil +} + + // Metadata functions func with_meta(a []MalType) (MalType, error) { @@ -204,6 +232,7 @@ func with_meta(a []MalType) (MalType, error) { case List: return List{tobj.Val,m}, nil case Vector: return Vector{tobj.Val,m}, nil case HashMap: return HashMap{tobj.Val,m}, nil + case Func: return Func{tobj.Fn,m}, nil case MalFunc: fn := tobj; fn.Meta = m; return fn, nil default: return nil, errors.New("with-meta not supported on type") } @@ -215,6 +244,7 @@ func meta(a []MalType) (MalType, error) { case List: return tobj.Meta, nil case Vector: return tobj.Meta, nil case HashMap: return tobj.Meta, nil + case Func: return tobj.Meta, nil case MalFunc: return tobj.Meta, nil default: return nil, errors.New("meta not supported on type") } @@ -319,11 +349,14 @@ var NS = map[string]MalType{ "count": count, "apply": apply, "map": do_map, + "conj": conj, "with-meta": with_meta, "meta": meta, "atom": func(a []MalType) (MalType, error) { return &Atom{a[0],nil}, nil }, + "atom?": func(a []MalType) (MalType, error) { + return Atom_Q(a[0]), nil }, "deref": deref, "reset!": reset_BANG, "swap!": swap_BANG, diff --git a/go/src/step5_tco/step5_tco.go b/go/src/step5_tco/step5_tco.go index 344a533..9e176bb 100644 --- a/go/src/step5_tco/step5_tco.go +++ b/go/src/step5_tco/step5_tco.go @@ -133,9 +133,9 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) if e != nil { return nil, e } } else { - fn, ok := f.(func([]MalType)(MalType, error)) + fn, ok := f.(Func) if !ok { return nil, errors.New("attempt to call non-function") } - return fn(el.(List).Val[1:]) + return fn.Fn(el.(List).Val[1:]) } } @@ -164,7 +164,7 @@ func rep(str string) (MalType, error) { func main() { // core.go: defined using go for k, v := range core.NS { - repl_env.Set(k, v) + repl_env.Set(k, Func{v.(func([]MalType)(MalType,error)),nil}) } // core.mal: defined using the language itself diff --git a/go/src/step6_file/step6_file.go b/go/src/step6_file/step6_file.go index 51fe3cb..748d158 100644 --- a/go/src/step6_file/step6_file.go +++ b/go/src/step6_file/step6_file.go @@ -134,9 +134,9 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) if e != nil { return nil, e } } else { - fn, ok := f.(func([]MalType)(MalType, error)) + fn, ok := f.(Func) if !ok { return nil, errors.New("attempt to call non-function") } - return fn(el.(List).Val[1:]) + return fn.Fn(el.(List).Val[1:]) } } @@ -165,10 +165,10 @@ func rep(str string) (MalType, error) { func main() { // core.go: defined using go for k, v := range core.NS { - repl_env.Set(k, v) + repl_env.Set(k, Func{v.(func([]MalType)(MalType,error)),nil}) } - repl_env.Set("eval", func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) }) + repl_env.Set("eval", Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) },nil}) repl_env.Set("*ARGV*", List{}) // core.mal: defined using the language itself @@ -182,7 +182,10 @@ func main() { args = append(args, a) } repl_env.Set("*ARGV*", List{args,nil}) - rep("(load-file \"" + os.Args[1] + "\")") + if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } os.Exit(0) } diff --git a/go/src/step7_quote/step7_quote.go b/go/src/step7_quote/step7_quote.go index abf7b45..999129e 100644 --- a/go/src/step7_quote/step7_quote.go +++ b/go/src/step7_quote/step7_quote.go @@ -167,9 +167,9 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) if e != nil { return nil, e } } else { - fn, ok := f.(func([]MalType)(MalType, error)) + fn, ok := f.(Func) if !ok { return nil, errors.New("attempt to call non-function") } - return fn(el.(List).Val[1:]) + return fn.Fn(el.(List).Val[1:]) } } @@ -198,10 +198,10 @@ func rep(str string) (MalType, error) { func main() { // core.go: defined using go for k, v := range core.NS { - repl_env.Set(k, v) + repl_env.Set(k, Func{v.(func([]MalType)(MalType,error)),nil}) } - repl_env.Set("eval", func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) }) + repl_env.Set("eval", Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) },nil}) repl_env.Set("*ARGV*", List{}) // core.mal: defined using the language itself @@ -215,7 +215,10 @@ func main() { args = append(args, a) } repl_env.Set("*ARGV*", List{args,nil}) - rep("(load-file \"" + os.Args[1] + "\")") + if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } os.Exit(0) } diff --git a/go/src/step8_macros/step8_macros.go b/go/src/step8_macros/step8_macros.go index 0feb739..3264159 100644 --- a/go/src/step8_macros/step8_macros.go +++ b/go/src/step8_macros/step8_macros.go @@ -206,9 +206,9 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) if e != nil { return nil, e } } else { - fn, ok := f.(func([]MalType)(MalType, error)) + fn, ok := f.(Func) if !ok { return nil, errors.New("attempt to call non-function") } - return fn(el.(List).Val[1:]) + return fn.Fn(el.(List).Val[1:]) } } @@ -237,15 +237,17 @@ func rep(str string) (MalType, error) { func main() { // core.go: defined using go for k, v := range core.NS { - repl_env.Set(k, v) + repl_env.Set(k, Func{v.(func([]MalType)(MalType,error)),nil}) } - repl_env.Set("eval", func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) }) + repl_env.Set("eval", Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) },nil}) repl_env.Set("*ARGV*", List{}) // core.mal: defined using the language itself rep("(def! not (fn* (a) (if a false true)))") rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))") + rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))") + rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))") // called with mal script to load and eval if len(os.Args) > 1 { @@ -254,7 +256,10 @@ func main() { args = append(args, a) } repl_env.Set("*ARGV*", List{args,nil}) - rep("(load-file \"" + os.Args[1] + "\")") + if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } os.Exit(0) } diff --git a/go/src/stepA_more/stepA_more.go b/go/src/stepA_more/stepA_more.go index d573ad0..322ee36 100644 --- a/go/src/stepA_more/stepA_more.go +++ b/go/src/stepA_more/stepA_more.go @@ -228,9 +228,9 @@ func EVAL(ast MalType, env EnvType) (MalType, error) { env, e = NewEnv(fn.Env, fn.Params, List{el.(List).Val[1:],nil}) if e != nil { return nil, e } } else { - fn, ok := f.(func([]MalType)(MalType, error)) + fn, ok := f.(Func) if !ok { return nil, errors.New("attempt to call non-function") } - return fn(el.(List).Val[1:]) + return fn.Fn(el.(List).Val[1:]) } } @@ -259,15 +259,18 @@ func rep(str string) (MalType, error) { func main() { // core.go: defined using go for k, v := range core.NS { - repl_env.Set(k, v) + repl_env.Set(k, Func{v.(func([]MalType)(MalType,error)),nil}) } - repl_env.Set("eval", func(a []MalType) (MalType, error) { - return EVAL(a[0], repl_env) }) + repl_env.Set("eval", Func{func(a []MalType) (MalType, error) { + return EVAL(a[0], repl_env) },nil}) repl_env.Set("*ARGV*", List{}) // core.mal: defined using the language itself + rep("(def! *host-language* \"go\")") rep("(def! not (fn* (a) (if a false true)))") rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))") + rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))") + rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))") // called with mal script to load and eval if len(os.Args) > 1 { @@ -276,11 +279,15 @@ func main() { args = append(args, a) } repl_env.Set("*ARGV*", List{args,nil}) - rep("(load-file \"" + os.Args[1] + "\")") + if _,e := rep("(load-file \"" + os.Args[1] + "\")"); e != nil { + fmt.Printf("Error: %v\n", e) + os.Exit(1) + } os.Exit(0) } // repl loop + rep("(println (str \"Mal [\" *host-language* \"]\"))") for { text, err := readline.Readline("user> ") text = strings.TrimRight(text, "\n"); diff --git a/go/src/types/types.go b/go/src/types/types.go index 616c8c7..613bfb5 100644 --- a/go/src/types/types.go +++ b/go/src/types/types.go @@ -65,6 +65,16 @@ func String_Q(obj MalType) bool { // Functions +type Func struct { + Fn func([]MalType) (MalType, error) + Meta MalType +} + +func Func_Q(obj MalType) bool { + if obj == nil { return false } + return reflect.TypeOf(obj).Name() == "Func" +} + type MalFunc struct { Eval func(MalType, EnvType) (MalType, error) Exp MalType @@ -97,6 +107,8 @@ func Apply(f_mt MalType, a []MalType) (MalType, error) { env, e := f.GenEnv(f.Env, f.Params, List{a,nil}) if e != nil { return nil, e } return f.Eval(f.Exp, env) + case Func: + return f.Fn(a) case func([]MalType)(MalType, error): return f(a) default: @@ -206,18 +218,25 @@ func Equal_Q(a MalType, b MalType) bool { } //av := reflect.ValueOf(a); bv := reflect.ValueOf(b) //fmt.Printf("here2: %#v\n", reflect.TypeOf(a).Name()) - switch reflect.TypeOf(a).Name() { - case "Symbol": + //switch reflect.TypeOf(a).Name() { + switch a.(type) { + case Symbol: return a.(Symbol).Val == b.(Symbol).Val - case "List": fallthrough - case "Vector": + case List: + as,_ := GetSlice(a); bs,_ := GetSlice(b) + if len(as) != len(bs) { return false } + for i := 0; i < len(as); i+=1 { + if !Equal_Q(as[i], bs[i]) { return false } + } + return true + case Vector: as,_ := GetSlice(a); bs,_ := GetSlice(b) if len(as) != len(bs) { return false } for i := 0; i < len(as); i+=1 { if !Equal_Q(as[i], bs[i]) { return false } } return true - case "HashMap": + case HashMap: return false default: return a == b |
