diff options
| author | Joel Martin <github@martintribe.org> | 2014-10-09 19:14:43 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-10-09 19:14:43 -0500 |
| commit | f2c9811fd8cbb205fad68952ebc1ba5d310f148d (patch) | |
| tree | 0a1d80a4ccfb6378014098475c70a90093b7efa7 | |
| parent | ad7e866ea1d4d035d876e58bca681a72099449af (diff) | |
| download | mal-f2c9811fd8cbb205fad68952ebc1ba5d310f148d.tar.gz mal-f2c9811fd8cbb205fad68952ebc1ba5d310f148d.zip | |
go: add hash-map support.
| -rw-r--r-- | go/src/core/core.go | 82 | ||||
| -rw-r--r-- | go/src/reader/reader.go | 14 | ||||
| -rw-r--r-- | go/src/step2_eval/step2_eval.go | 2 | ||||
| -rw-r--r-- | go/src/step3_env/step3_env.go | 2 | ||||
| -rw-r--r-- | go/src/step4_if_fn_do/step4_if_fn_do.go | 2 | ||||
| -rw-r--r-- | go/src/step5_tco/step5_tco.go | 2 | ||||
| -rw-r--r-- | go/src/step6_file/step6_file.go | 2 | ||||
| -rw-r--r-- | go/src/step7_quote/step7_quote.go | 2 | ||||
| -rw-r--r-- | go/src/step8_macros/step8_macros.go | 2 | ||||
| -rw-r--r-- | go/src/stepA_more/stepA_more.go | 2 | ||||
| -rw-r--r-- | go/src/types/types.go | 28 |
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 |
