diff --git a/pkg/lang/set.go b/pkg/lang/set.go index d468896..f3d363c 100644 --- a/pkg/lang/set.go +++ b/pkg/lang/set.go @@ -9,22 +9,22 @@ type Set struct { meta IPersistentMap hash, hasheq uint32 - vals []interface{} + hashMap IPersistentMap } -type PersistentHashSet = Set // hack until we have a proper persistent hash set +type PersistentHashSet = Set -func CreatePersistentTreeSet(keys ISeq) interface{} { +func CreatePersistentTreeSet(keys ISeq) any { // TODO: implement return NewSet(seqToSlice(keys)...) } -func CreatePersistentTreeSetWithComparator(comparator IFn, keys ISeq) interface{} { +func CreatePersistentTreeSetWithComparator(comparator IFn, keys ISeq) any { // TODO: implement return NewSet(seqToSlice(keys)...) } -func NewSet(vals ...interface{}) *Set { +func NewSet(vals ...any) *Set { set, err := NewSet2(vals...) if err != nil { panic(err) @@ -32,19 +32,16 @@ func NewSet(vals ...interface{}) *Set { return set } -func NewSet2(vals ...interface{}) (*Set, error) { - // check for duplicates +func NewSet2(vals ...any) (*Set, error) { + set := &Set{ + hashMap: NewPersistentHashMap(), + } for i := 0; i < len(vals); i++ { - for j := i + 1; j < len(vals); j++ { - if Equiv(vals[i], vals[j]) { - return nil, NewIllegalArgumentError(fmt.Sprintf("duplicate key: %v", vals[i])) - } - } + val := vals[i] + set.hashMap = set.hashMap.Assoc(val, true).(IPersistentMap) } - return &Set{ - vals: vals, - }, nil + return set, nil } var ( @@ -55,16 +52,15 @@ var ( emptySet = NewSet() ) -func (s *Set) Get(key interface{}) interface{} { - for _, v := range s.vals { - if Equiv(v, key) { - return v - } +func (s *Set) Get(key any) any { + val := s.hashMap.ValAt(key) + if val == true { + return key } return nil } -func (s *Set) Invoke(args ...interface{}) interface{} { +func (s *Set) Invoke(args ...any) any { if len(args) != 1 { panic(fmt.Errorf("set apply expects 1 argument, got %d", len(args))) } @@ -72,40 +68,36 @@ func (s *Set) Invoke(args ...interface{}) interface{} { return s.Get(args[0]) } -func (s *Set) ApplyTo(args ISeq) interface{} { +func (s *Set) ApplyTo(args ISeq) any { return s.Invoke(seqToSlice(args)...) } -func (s *Set) Cons(v interface{}) Conser { +func (s *Set) Cons(v any) Conser { if s.Contains(v) { return s } - return NewSet(append(s.vals, v)...) + return &Set{ + meta: s.meta, + hashMap: s.hashMap.Assoc(v, true).(IPersistentMap), + } } -func (s *Set) Disjoin(v interface{}) IPersistentSet { - for i, val := range s.vals { - if Equiv(val, v) { - newItems := make([]interface{}, len(s.vals)-1) - copy(newItems, s.vals[:i]) - copy(newItems[i:], s.vals[i+1:]) - return NewSet(newItems...) - } +func (s *Set) Disjoin(v any) IPersistentSet { + if !s.Contains(v) { + return s + } + return &Set{ + meta: s.meta, + hashMap: s.hashMap.Without(v).(IPersistentMap), } - return s } -func (s *Set) Contains(v interface{}) bool { - for _, val := range s.vals { - if Equiv(val, v) { - return true - } - } - return false +func (s *Set) Contains(v any) bool { + return s.hashMap.ContainsKey(v) } func (s *Set) Count() int { - return len(s.vals) + return s.hashMap.Count() } func (s *Set) xxx_counted() {} @@ -122,7 +114,7 @@ func (s *Set) String() string { return PrintString(s) } -func (s *Set) Equals(v2 interface{}) bool { +func (s *Set) Equals(v2 any) bool { if s == v2 { return true } @@ -143,10 +135,10 @@ func (s *Set) Equals(v2 interface{}) bool { } func (s *Set) Seq() ISeq { - if s.Count() == 0 { + if s.hashMap.Count() == 0 { return nil } - return NewSliceSeq(s.vals) + return NewMapKeySeq(Seq(s.hashMap)) } func (s *Set) Equiv(o any) bool { @@ -165,15 +157,14 @@ func (s *Set) Meta() IPersistentMap { return s.meta } -func (s *Set) WithMeta(meta IPersistentMap) interface{} { +func (s *Set) WithMeta(meta IPersistentMap) any { if meta == s.meta { return s } - return &Set{ - meta: meta, - vals: s.vals, - } + cpy := *s + cpy.meta = meta + return &cpy } func (s *Set) AsTransient() ITransientCollection { @@ -185,7 +176,7 @@ type TransientSet struct { *Set } -func (s *TransientSet) Conj(v interface{}) Conjer { +func (s *TransientSet) Conj(v any) Conjer { return &TransientSet{Set: s.Set.Cons(v).(*Set)} } diff --git a/pkg/lang/symbol.go b/pkg/lang/symbol.go index c0b2a9c..514d7fe 100644 --- a/pkg/lang/symbol.go +++ b/pkg/lang/symbol.go @@ -14,6 +14,8 @@ type Symbol struct { var ( symbolRegex = regexp.MustCompile(`^(?:[^0-9/].*/)?(?:/|[^0-9/][^/]*)$`) + + _ IFn = (*Symbol)(nil) ) // NewSymbol creates a new symbol. @@ -34,7 +36,7 @@ func NewSymbol(s string) *Symbol { } } -func InternSymbol(ns, name interface{}) *Symbol { +func InternSymbol(ns, name any) *Symbol { if ns == nil { return NewSymbol(name.(string)) } @@ -127,7 +129,7 @@ func (s *Symbol) String() string { return s.ns + "/" + s.name } -func (s *Symbol) Equals(v interface{}) bool { +func (s *Symbol) Equals(v any) bool { if s == v { return true } @@ -145,7 +147,7 @@ func (s *Symbol) Meta() IPersistentMap { return s.meta } -func (s *Symbol) WithMeta(meta IPersistentMap) interface{} { +func (s *Symbol) WithMeta(meta IPersistentMap) any { if s.meta == meta { return s } @@ -160,3 +162,18 @@ func (s *Symbol) Hash() uint32 { h.Write([]byte(s.ns + "/" + s.name)) return h.Sum32() ^ symbolHashMask } + +func (s *Symbol) Invoke(args ...any) any { + switch len(args) { + case 1: + return Get(args[0], s) + case 2: + return GetDefault(args[0], s, args[1]) + default: + panic(NewIllegalArgumentError("symbol invoke expects 1 or 2 arguments")) + } +} + +func (s *Symbol) ApplyTo(args ISeq) any { + return s.Invoke(seqToSlice(args)...) +} diff --git a/pkg/reader/testdata/reader/set00.glj b/pkg/reader/testdata/reader/set00.glj index a6b83a0..327b712 100644 --- a/pkg/reader/testdata/reader/set00.glj +++ b/pkg/reader/testdata/reader/set00.glj @@ -1 +1 @@ -#{:a :b :c} +#{:a} diff --git a/pkg/reader/testdata/reader/set00.out b/pkg/reader/testdata/reader/set00.out index a6b83a0..327b712 100644 --- a/pkg/reader/testdata/reader/set00.out +++ b/pkg/reader/testdata/reader/set00.out @@ -1 +1 @@ -#{:a :b :c} +#{:a} diff --git a/pkg/stdlib/clojure/core/loader.go b/pkg/stdlib/clojure/core/loader.go index ac7e21a..56e47e8 100644 --- a/pkg/stdlib/clojure/core/loader.go +++ b/pkg/stdlib/clojure/core/loader.go @@ -3136,7 +3136,7 @@ func LoadNS() { // *loaded-libs* { tmp0 := sym__STAR_loaded_DASH_libs_STAR_.WithMeta(lang.NewMap(kw_dynamic, true, kw_file, "clojure/core.glj", kw_line, int(5809), kw_column, int(10), kw_end_DASH_line, int(5812), kw_end_DASH_column, int(15), kw_ns, lang.FindOrCreateNamespace(sym_clojure_DOT_core))).(*lang.Symbol) - tmp1 := lang.NewRef(lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{sym_clojure_DOT_core_DOT_protocols, sym_clojure_DOT_string, sym_glojure_DOT_go_DOT_io, sym_user}))) + tmp1 := lang.NewRef(lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{sym_clojure_DOT_string, sym_user, sym_clojure_DOT_core_DOT_protocols, sym_glojure_DOT_go_DOT_io}))) var_clojure_DOT_core__STAR_loaded_DASH_libs_STAR_ = ns.InternWithValue(tmp0, tmp1, true) if tmp0.Meta() != nil { var_clojure_DOT_core__STAR_loaded_DASH_libs_STAR_.SetMeta(tmp0.Meta().(lang.IPersistentMap)) @@ -10862,7 +10862,7 @@ func LoadNS() { v2 = tmp1 _ = v2 } - tmp0 := sym_get.WithMeta(lang.NewMap(kw_arglists, lang.NewList(lang.NewVector(sym_map, sym_key), lang.NewVector(sym_map, sym_key, sym_not_DASH_found)), kw_inline, tmp1, kw_doc, "Returns the value mapped to key, not-found or nil if key not present\n in associative collection, set, string, array, or ILookup instance.", kw_file, "clojure/core.glj", kw_inline_DASH_arities, lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{int64(2), int64(3)})), kw_added, "1.0", kw_ns, lang.FindOrCreateNamespace(sym_clojure_DOT_core), kw_end_DASH_column, int(9), kw_column, int(7), kw_line, int(1488), kw_end_DASH_line, int(1488))).(*lang.Symbol) + tmp0 := sym_get.WithMeta(lang.NewMap(kw_arglists, lang.NewList(lang.NewVector(sym_map, sym_key), lang.NewVector(sym_map, sym_key, sym_not_DASH_found)), kw_inline, tmp1, kw_doc, "Returns the value mapped to key, not-found or nil if key not present\n in associative collection, set, string, array, or ILookup instance.", kw_file, "clojure/core.glj", kw_inline_DASH_arities, lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{int64(3), int64(2)})), kw_added, "1.0", kw_ns, lang.FindOrCreateNamespace(sym_clojure_DOT_core), kw_end_DASH_column, int(9), kw_column, int(7), kw_line, int(1488), kw_end_DASH_line, int(1488))).(*lang.Symbol) var tmp2 lang.FnFunc tmp2 = lang.NewFnFunc(func(args ...any) any { switch len(args) { @@ -12698,7 +12698,7 @@ func LoadNS() { v2 = tmp1 _ = v2 } - tmp0 := sym_nth.WithMeta(lang.NewMap(kw_arglists, lang.NewList(lang.NewVector(sym_coll, sym_index), lang.NewVector(sym_coll, sym_index, sym_not_DASH_found)), kw_inline, tmp1, kw_doc, "Returns the value at the index. get returns nil if index out of\n bounds, nth throws an exception unless not-found is supplied. nth\n also works for strings, Java arrays, regex Matchers and Lists, and,\n in O(n) time, for sequences.", kw_file, "clojure/core.glj", kw_inline_DASH_arities, lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{int64(2), int64(3)})), kw_added, "1.0", kw_ns, lang.FindOrCreateNamespace(sym_clojure_DOT_core), kw_end_DASH_column, int(9), kw_column, int(7), kw_line, int(884), kw_end_DASH_line, int(884))).(*lang.Symbol) + tmp0 := sym_nth.WithMeta(lang.NewMap(kw_arglists, lang.NewList(lang.NewVector(sym_coll, sym_index), lang.NewVector(sym_coll, sym_index, sym_not_DASH_found)), kw_inline, tmp1, kw_doc, "Returns the value at the index. get returns nil if index out of\n bounds, nth throws an exception unless not-found is supplied. nth\n also works for strings, Java arrays, regex Matchers and Lists, and,\n in O(n) time, for sequences.", kw_file, "clojure/core.glj", kw_inline_DASH_arities, lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{int64(3), int64(2)})), kw_added, "1.0", kw_ns, lang.FindOrCreateNamespace(sym_clojure_DOT_core), kw_end_DASH_column, int(9), kw_column, int(7), kw_line, int(884), kw_end_DASH_line, int(884))).(*lang.Symbol) var tmp2 lang.FnFunc tmp2 = lang.NewFnFunc(func(args ...any) any { switch len(args) { @@ -32660,8 +32660,8 @@ func LoadNS() { var v8 any = tmp7 _ = v8 var tmp9 any - tmp10 := checkDerefVar(var_clojure_DOT_core__LT_) - tmp11 := checkDerefVar(var_clojure_DOT_core__LT__EQ_) + tmp10 := checkDerefVar(var_clojure_DOT_core__LT__EQ_) + tmp11 := checkDerefVar(var_clojure_DOT_core__LT_) tmp12 := lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{tmp10, tmp11})) tmp13 := lang.NewMap(kw_file, "clojure/core.glj", kw_line, int(5150), kw_column, int(11), kw_end_DASH_line, int(5150), kw_end_DASH_column, int(17)) tmp14, err := lang.WithMeta(tmp12, tmp13.(lang.IPersistentMap)) @@ -53465,7 +53465,7 @@ func LoadNS() { var tmp19 any { // let // let binding "supported" - tmp20 := lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{kw_as, kw_reload, kw_reload_DASH_all, kw_require, kw_use, kw_verbose, kw_refer, kw_as_DASH_alias})) + tmp20 := lang.CreatePersistentTreeSet(lang.NewSliceSeq([]any{kw_use, kw_refer, kw_verbose, kw_require, kw_reload_DASH_all, kw_reload, kw_as_DASH_alias, kw_as})) tmp21 := lang.NewMap(kw_file, "clojure/core.glj", kw_line, int(5951), kw_column, int(21), kw_end_DASH_line, int(5951), kw_end_DASH_column, int(86)) tmp22, err := lang.WithMeta(tmp20, tmp21.(lang.IPersistentMap)) if err != nil { @@ -55433,10 +55433,10 @@ func LoadNS() { tmp51 := reflect.TypeOf((*lang.IPersistentCollection)(nil)).Elem() tmp1.PreferMethod(tmp50, tmp51) tmp52 := reflect.TypeOf((*lang.IRecord)(nil)).Elem() - tmp53 := reflect.TypeOf((*lang.IPersistentMap)(nil)).Elem() + tmp53 := reflect.TypeOf((*lang.IPersistentCollection)(nil)).Elem() tmp1.PreferMethod(tmp52, tmp53) tmp54 := reflect.TypeOf((*lang.IRecord)(nil)).Elem() - tmp55 := reflect.TypeOf((*lang.IPersistentCollection)(nil)).Elem() + tmp55 := reflect.TypeOf((*lang.IPersistentMap)(nil)).Elem() tmp1.PreferMethod(tmp54, tmp55) var_clojure_DOT_core_print_DASH_dup = ns.InternWithValue(tmp0, tmp1, true) if tmp0.Meta() != nil {