package object import ( "bytes" "fmt" "hash/fnv" "strings" ) type HashKey struct { Type ObjectType Value uint64 } func (b *Boolean) HashKey() HashKey { var value uint64 if b.Value { value = 1 } else { value = 0 } return HashKey{Type: b.Type(), Value: value} } func (i *Integer) HashKey() HashKey { return HashKey{Type: i.Type(), Value: uint64(i.Value)} } func (s *String) HashKey() HashKey { h := fnv.New64a() h.Write([]byte(s.Value)) return HashKey{Type: s.Type(), Value: h.Sum64()} } type HashPair struct { Key Object Value Object } type Hash struct { Pairs map[HashKey]HashPair } func (h *Hash) Len() int { return len(h.Pairs) } func (h *Hash) Bool() bool { return len(h.Pairs) > 0 } func (h *Hash) Type() ObjectType { return HASH_OBJ } func (h *Hash) Inspect() string { var out bytes.Buffer pairs := []string{} for _, pair := range h.Pairs { pairs = append(pairs, fmt.Sprintf("%s: %s", pair.Key.Inspect(), pair.Value.Inspect())) } out.WriteString("{") out.WriteString(strings.Join(pairs, ", ")) out.WriteString("}") return out.String() } func (h *Hash) String() string { return h.Inspect() } func (h *Hash) Compare(other Object) int { if obj, ok := other.(*Hash); ok { if len(h.Pairs) != len(obj.Pairs) { return -1 } for _, pair := range h.Pairs { left := pair.Value hashed := left.(Hashable) right, ok := obj.Pairs[hashed.HashKey()] if !ok { return -1 } cmp, ok := left.(Comparable) if !ok { return -1 } if cmp.Compare(right.Value) != 0 { return cmp.Compare(right.Value) } } return 0 } return -1 }