diff options
Diffstat (limited to 'go/src/core')
| -rw-r--r-- | go/src/core/core.go | 104 |
1 files changed, 81 insertions, 23 deletions
diff --git a/go/src/core/core.go b/go/src/core/core.go index cdb7d8f..f5d5842 100644 --- a/go/src/core/core.go +++ b/go/src/core/core.go @@ -47,18 +47,21 @@ func slurp(a []MalType) (MalType, error) { // Hash Map functions +func copy_hash_map(hm HashMap) (HashMap) { + new_hm := HashMap{map[string]MalType{},nil} + for k, v := range hm.Val { new_hm.Val[k] = v } + return new_hm +} + 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 } + new_hm := copy_hash_map(a[0].(HashMap)) 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] + new_hm.Val[key.(string)] = a[i+1] } return new_hm, nil } @@ -66,14 +69,11 @@ func assoc(a []MalType) (MalType, error) { 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 } + 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,key.(string)) + delete(new_hm.Val,key.(string)) } return new_hm, nil } @@ -83,32 +83,32 @@ func get(a []MalType) (MalType, error) { 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 + return a[0].(HashMap).Val[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)] + _, ok := hm.(HashMap).Val[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) { + for k, _ := range a[0].(HashMap).Val { slc = append(slc, k) } - return List{slc}, nil + return List{slc,nil}, 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) { + for _, v := range a[0].(HashMap).Val { slc = append(slc, v) } - return List{slc}, nil + return List{slc,nil}, nil } @@ -118,7 +118,7 @@ func cons(a []MalType) (MalType, error) { val := a[0] lst, e := GetSlice(a[1]); if e != nil { return nil, e } - return List{append([]MalType{val}, lst...)}, nil + return List{append([]MalType{val}, lst...),nil}, nil } func concat(a []MalType) (MalType, error) { @@ -128,7 +128,7 @@ func concat(a []MalType) (MalType, error) { slc2, e := GetSlice(a[i]); if e != nil { return nil, e } slc1 = append(slc1, slc2...) } - return List{slc1}, nil + return List{slc1,nil}, nil } func nth(a []MalType) (MalType, error) { @@ -147,7 +147,7 @@ func first(a []MalType) (MalType, error) { func rest(a []MalType) (MalType, error) { slc, e := GetSlice(a[0]); if e != nil { return nil, e } if len(slc) == 0 { return List{}, nil } - return List{slc[1:]}, nil + return List{slc[1:],nil}, nil } @@ -192,10 +192,60 @@ func do_map(a []MalType) (MalType, error) { results = append(results, res) if e != nil { return nil, e } } - return List{results}, nil + return List{results,nil}, nil } +// Metadata functions +func with_meta(a []MalType) (MalType, error) { + if len(a) != 2 { return nil, errors.New("with-meta requires 2 args") } + obj := a[0]; m := a[1] + switch tobj := obj.(type) { + 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 MalFunc: fn := tobj; fn.Meta = m; return fn, nil + default: return nil, errors.New("with-meta not supported on type") + } +} + +func meta(a []MalType) (MalType, error) { + obj := a[0] + switch tobj := obj.(type) { + case List: return tobj.Meta, nil + case Vector: return tobj.Meta, nil + case HashMap: return tobj.Meta, nil + case MalFunc: return tobj.Meta, nil + default: return nil, errors.New("meta not supported on type") + } +} + + +// Atom functions +func deref(a []MalType) (MalType, error) { + if !Atom_Q(a[0]) { return nil, errors.New("deref called with non-atom") } + return a[0].(*Atom).Val, nil +} + +func reset_BANG(a []MalType) (MalType, error) { + if !Atom_Q(a[0]) { return nil, errors.New("reset! called with non-atom") } + a[0].(*Atom).Set(a[1]) + return a[1], nil +} + +func swap_BANG(a []MalType) (MalType, error) { + if !Atom_Q(a[0]) { return nil, errors.New("swap! called with non-atom") } + if len(a) < 2 { return nil, errors.New("swap! requires at least 2 args") } + atm := a[0].(*Atom) + args := []MalType{atm.Val} + f := a[1] + args = append(args, a[2:]...) + res, e := Apply(f, args) + if e != nil { return nil, e } + atm.Set(res) + return res, nil +} + // core namespace var NS = map[string]MalType{ @@ -239,15 +289,15 @@ var NS = map[string]MalType{ return a[0].(int) / a[1].(int), nil }, "list": func(a []MalType) (MalType, error) { - return List{a}, nil }, + return List{a,nil}, nil }, "list?": func(a []MalType) (MalType, error) { return List_Q(a[0]), nil }, "vector": func(a []MalType) (MalType, error) { - return Vector{a}, nil }, + return Vector{a,nil}, nil }, "vector?": func(a []MalType) (MalType, error) { return Vector_Q(a[0]), nil }, "hash-map": func(a []MalType) (MalType, error) { - return NewHashMap(List{a}) }, + return NewHashMap(List{a,nil}) }, "map?": func(a []MalType) (MalType, error) { return HashMap_Q(a[0]), nil }, "assoc": assoc, @@ -269,4 +319,12 @@ var NS = map[string]MalType{ "count": count, "apply": apply, "map": do_map, + + "with-meta": with_meta, + "meta": meta, + "atom": func(a []MalType) (MalType, error) { + return &Atom{a[0],nil}, nil }, + "deref": deref, + "reset!": reset_BANG, + "swap!": swap_BANG, } |
