aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-10-09 19:14:43 -0500
committerJoel Martin <github@martintribe.org>2014-10-09 19:14:43 -0500
commitf2c9811fd8cbb205fad68952ebc1ba5d310f148d (patch)
tree0a1d80a4ccfb6378014098475c70a90093b7efa7
parentad7e866ea1d4d035d876e58bca681a72099449af (diff)
downloadmal-f2c9811fd8cbb205fad68952ebc1ba5d310f148d.tar.gz
mal-f2c9811fd8cbb205fad68952ebc1ba5d310f148d.zip
go: add hash-map support.
-rw-r--r--go/src/core/core.go82
-rw-r--r--go/src/reader/reader.go14
-rw-r--r--go/src/step2_eval/step2_eval.go2
-rw-r--r--go/src/step3_env/step3_env.go2
-rw-r--r--go/src/step4_if_fn_do/step4_if_fn_do.go2
-rw-r--r--go/src/step5_tco/step5_tco.go2
-rw-r--r--go/src/step6_file/step6_file.go2
-rw-r--r--go/src/step7_quote/step7_quote.go2
-rw-r--r--go/src/step8_macros/step8_macros.go2
-rw-r--r--go/src/stepA_more/stepA_more.go2
-rw-r--r--go/src/types/types.go28
11 files changed, 118 insertions, 22 deletions
diff --git a/go/src/core/core.go b/go/src/core/core.go
index cd63930..cdb7d8f 100644
--- a/go/src/core/core.go
+++ b/go/src/core/core.go
@@ -46,6 +46,72 @@ func slurp(a []MalType) (MalType, error) {
}
+// Hash Map functions
+func assoc(a []MalType) (MalType, error) {
+ if len(a) <3 { return nil, errors.New("assoc requires at least 3 arguments") }
+ if (len(a) % 2 != 1) { return nil, errors.New("assoc requires odd number of arguments") }
+ if !HashMap_Q(a[0]) { return nil, errors.New("assoc called on non-hash map") }
+ old_hm := a[0].(map[string]MalType)
+ new_hm := map[string]MalType{}
+ // copy
+ for k, v := range old_hm { new_hm[k] = v }
+ for i := 1; i < len(a); i+=2 {
+ key := a[i]
+ if !String_Q(key) { return nil, errors.New("assoc called with non-string key") }
+ new_hm[key.(string)] = a[i+1]
+ }
+ return new_hm, nil
+}
+
+func dissoc(a []MalType) (MalType, error) {
+ if len(a) <2 { return nil, errors.New("dissoc requires at least 3 arguments") }
+ if !HashMap_Q(a[0]) { return nil, errors.New("dissoc called on non-hash map") }
+ old_hm := a[0].(map[string]MalType)
+ new_hm := map[string]MalType{}
+ // copy
+ for k, v := range old_hm { new_hm[k] = v }
+ 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,key.(string))
+ }
+ return new_hm, nil
+}
+
+func get(a []MalType) (MalType, error) {
+ if len(a) != 2 { return nil, errors.New("get requires 2 arguments") }
+ if Nil_Q(a[0]) { return nil, nil }
+ if !HashMap_Q(a[0]) { return nil, errors.New("get called on non-hash map") }
+ if !String_Q(a[1]) { return nil, errors.New("get called with non-string key") }
+ return a[0].(map[string]MalType)[a[1].(string)], nil
+}
+
+func contains_Q(hm MalType, key MalType) (MalType, error) {
+ if Nil_Q(hm) { return nil, nil }
+ if !HashMap_Q(hm) { return nil, errors.New("get called on non-hash map") }
+ if !String_Q(key) { return nil, errors.New("get called with non-string key") }
+ _, ok := hm.(map[string]MalType)[key.(string)]
+ return ok, nil
+}
+
+func keys(a []MalType) (MalType, error) {
+ if !HashMap_Q(a[0]) { return nil, errors.New("keys called on non-hash map") }
+ slc := []MalType{}
+ for k, _ := range a[0].(map[string]MalType) {
+ slc = append(slc, k)
+ }
+ return List{slc}, nil
+}
+func vals(a []MalType) (MalType, error) {
+ if !HashMap_Q(a[0]) { return nil, errors.New("keys called on non-hash map") }
+ slc := []MalType{}
+ for _, v := range a[0].(map[string]MalType) {
+ slc = append(slc, v)
+ }
+ return List{slc}, nil
+}
+
+
// Sequence functions
func cons(a []MalType) (MalType, error) {
@@ -98,6 +164,7 @@ func count(a []MalType) (MalType, error) {
switch obj := a[0].(type) {
case List: return len(obj.Val), nil
case Vector: return len(obj.Val), nil
+ case map[string]MalType: return len(obj), nil
case nil: return 0, nil
default: return nil, errors.New("Count called on non-sequence")
}
@@ -175,6 +242,21 @@ var NS = map[string]MalType{
return List{a}, nil },
"list?": func(a []MalType) (MalType, error) {
return List_Q(a[0]), nil },
+ "vector": func(a []MalType) (MalType, error) {
+ return Vector{a}, nil },
+ "vector?": func(a []MalType) (MalType, error) {
+ return Vector_Q(a[0]), nil },
+ "hash-map": func(a []MalType) (MalType, error) {
+ return NewHashMap(List{a}) },
+ "map?": func(a []MalType) (MalType, error) {
+ return HashMap_Q(a[0]), nil },
+ "assoc": assoc,
+ "dissoc": dissoc,
+ "get": get,
+ "contains?": func(a []MalType) (MalType, error) {
+ return contains_Q(a[0], a[1]) },
+ "keys": keys,
+ "vals": vals,
"sequential?": func(a []MalType) (MalType, error) {
return Sequential_Q(a[0]), nil },
diff --git a/go/src/reader/reader.go b/go/src/reader/reader.go
index f8c15d5..2ac5a08 100644
--- a/go/src/reader/reader.go
+++ b/go/src/reader/reader.go
@@ -105,20 +105,8 @@ func read_vector(rdr Reader) (MalType, error) {
func read_hash_map(rdr Reader) (MalType, error) {
mal_lst, e := read_list(rdr, "{", "}")
- lst := mal_lst.(List).Val
if e != nil { return nil, e }
- if len(lst) % 2 == 1 {
- return nil, errors.New("Odd number of hash map arguments")
- }
- m := map[string]MalType{}
- for i := 0; i < len(lst); i+=2 {
- str, ok := lst[i].(string)
- if !ok {
- return nil, errors.New("expected hash-map key string")
- }
- m[str] = lst[i+1]
- }
- return m, nil
+ return NewHashMap(mal_lst)
}
func read_form(rdr Reader) (MalType, error) {
diff --git a/go/src/step2_eval/step2_eval.go b/go/src/step2_eval/step2_eval.go
index 9b3aa28..d28de20 100644
--- a/go/src/step2_eval/step2_eval.go
+++ b/go/src/step2_eval/step2_eval.go
@@ -42,7 +42,7 @@ func eval_ast(ast MalType, env map[string]MalType) (MalType, error) {
lst = append(lst, exp)
}
return Vector{lst}, nil
- } else if Hash_Map_Q(ast) {
+ } else if HashMap_Q(ast) {
m := ast.(map[string]MalType)
new_hm := map[string]MalType{}
for k, v := range m {
diff --git a/go/src/step3_env/step3_env.go b/go/src/step3_env/step3_env.go
index 7e45a39..eea250f 100644
--- a/go/src/step3_env/step3_env.go
+++ b/go/src/step3_env/step3_env.go
@@ -40,7 +40,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
lst = append(lst, exp)
}
return Vector{lst}, nil
- } else if Hash_Map_Q(ast) {
+ } else if HashMap_Q(ast) {
m := ast.(map[string]MalType)
new_hm := map[string]MalType{}
for k, v := range m {
diff --git a/go/src/step4_if_fn_do/step4_if_fn_do.go b/go/src/step4_if_fn_do/step4_if_fn_do.go
index 760919b..6a35b85 100644
--- a/go/src/step4_if_fn_do/step4_if_fn_do.go
+++ b/go/src/step4_if_fn_do/step4_if_fn_do.go
@@ -41,7 +41,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
lst = append(lst, exp)
}
return Vector{lst}, nil
- } else if Hash_Map_Q(ast) {
+ } else if HashMap_Q(ast) {
m := ast.(map[string]MalType)
new_hm := map[string]MalType{}
for k, v := range m {
diff --git a/go/src/step5_tco/step5_tco.go b/go/src/step5_tco/step5_tco.go
index c7c2ab5..75e1979 100644
--- a/go/src/step5_tco/step5_tco.go
+++ b/go/src/step5_tco/step5_tco.go
@@ -41,7 +41,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
lst = append(lst, exp)
}
return Vector{lst}, nil
- } else if Hash_Map_Q(ast) {
+ } else if HashMap_Q(ast) {
m := ast.(map[string]MalType)
new_hm := map[string]MalType{}
for k, v := range m {
diff --git a/go/src/step6_file/step6_file.go b/go/src/step6_file/step6_file.go
index 056fe39..912d932 100644
--- a/go/src/step6_file/step6_file.go
+++ b/go/src/step6_file/step6_file.go
@@ -42,7 +42,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
lst = append(lst, exp)
}
return Vector{lst}, nil
- } else if Hash_Map_Q(ast) {
+ } else if HashMap_Q(ast) {
m := ast.(map[string]MalType)
new_hm := map[string]MalType{}
for k, v := range m {
diff --git a/go/src/step7_quote/step7_quote.go b/go/src/step7_quote/step7_quote.go
index 68c2a85..0877bbb 100644
--- a/go/src/step7_quote/step7_quote.go
+++ b/go/src/step7_quote/step7_quote.go
@@ -71,7 +71,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
lst = append(lst, exp)
}
return Vector{lst}, nil
- } else if Hash_Map_Q(ast) {
+ } else if HashMap_Q(ast) {
m := ast.(map[string]MalType)
new_hm := map[string]MalType{}
for k, v := range m {
diff --git a/go/src/step8_macros/step8_macros.go b/go/src/step8_macros/step8_macros.go
index 82572d3..7a5c0e5 100644
--- a/go/src/step8_macros/step8_macros.go
+++ b/go/src/step8_macros/step8_macros.go
@@ -99,7 +99,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
lst = append(lst, exp)
}
return Vector{lst}, nil
- } else if Hash_Map_Q(ast) {
+ } else if HashMap_Q(ast) {
m := ast.(map[string]MalType)
new_hm := map[string]MalType{}
for k, v := range m {
diff --git a/go/src/stepA_more/stepA_more.go b/go/src/stepA_more/stepA_more.go
index be693f6..0194862 100644
--- a/go/src/stepA_more/stepA_more.go
+++ b/go/src/stepA_more/stepA_more.go
@@ -99,7 +99,7 @@ func eval_ast(ast MalType, env EnvType) (MalType, error) {
lst = append(lst, exp)
}
return Vector{lst}, nil
- } else if Hash_Map_Q(ast) {
+ } else if HashMap_Q(ast) {
m := ast.(map[string]MalType)
new_hm := map[string]MalType{}
for k, v := range m {
diff --git a/go/src/types/types.go b/go/src/types/types.go
index a489aa3..03269f5 100644
--- a/go/src/types/types.go
+++ b/go/src/types/types.go
@@ -62,6 +62,15 @@ func Symbol_Q(obj MalType) bool {
}
+// Strings
+func String_Q(obj MalType) bool {
+ switch obj.(type) {
+ case string: return true
+ default: return false
+ }
+}
+
+
// Functions
type MalFunc struct {
Eval func(MalType, EnvType) (MalType, error)
@@ -141,7 +150,24 @@ func GetSlice(seq MalType) ([]MalType, error) {
}
// Hash Maps
-func Hash_Map_Q(obj MalType) bool {
+func NewHashMap(seq MalType) (MalType, error) {
+ lst, e := GetSlice(seq)
+ if e != nil { return nil, e }
+ if len(lst) % 2 == 1 {
+ return nil, errors.New("Odd number of arguments to NewHashMap")
+ }
+ m := map[string]MalType{}
+ for i := 0; i < len(lst); i+=2 {
+ str, ok := lst[i].(string)
+ if !ok {
+ return nil, errors.New("expected hash-map key string")
+ }
+ m[str] = lst[i+1]
+ }
+ return m, nil
+}
+
+func HashMap_Q(obj MalType) bool {
switch obj.(type) {
case map[string]MalType: return true
default: return false