aboutsummaryrefslogtreecommitdiff
path: root/go/src
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-10-09 22:10:15 -0500
committerJoel Martin <github@martintribe.org>2015-01-06 21:57:02 -0600
commit1771ab50b87c745181e4e30f94b63e3f23d33dac (patch)
treec1c9b5d80ba9261c5f16bab1b52c1bb0f559407c /go/src
parentf2544a9467ea032aff505b3ced3b4b3510a828fe (diff)
downloadmal-1771ab50b87c745181e4e30f94b63e3f23d33dac.tar.gz
mal-1771ab50b87c745181e4e30f94b63e3f23d33dac.zip
go: update README. Backport Func usage.
Diffstat (limited to 'go/src')
-rw-r--r--go/src/core/core.go33
-rw-r--r--go/src/step5_tco/step5_tco.go6
-rw-r--r--go/src/step6_file/step6_file.go15
-rw-r--r--go/src/step7_quote/step7_quote.go15
-rw-r--r--go/src/step8_macros/step8_macros.go17
-rw-r--r--go/src/stepA_more/stepA_more.go19
-rw-r--r--go/src/types/types.go29
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