119 lines
1.9 KiB
Go
119 lines
1.9 KiB
Go
package object
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type HashKey struct {
|
|
Type Type
|
|
Value uint64
|
|
}
|
|
|
|
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() Type {
|
|
return HashType
|
|
}
|
|
|
|
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) Add(other Object) (Object, error) {
|
|
if other.Type() != h.Type() {
|
|
return nil, NewBinaryOpError(h, other, "+")
|
|
}
|
|
|
|
pairs := make(map[HashKey]HashPair)
|
|
for k, v := range h.Pairs {
|
|
pairs[k] = v
|
|
}
|
|
for k, v := range other.(*Hash).Pairs {
|
|
pairs[k] = v
|
|
}
|
|
return &Hash{Pairs: pairs}, nil
|
|
}
|
|
|
|
func (h *Hash) Get(index Object) (Object, error) {
|
|
key, ok := index.(Hasher)
|
|
if !ok {
|
|
return nil, fmt.Errorf("invalid hash key %s", index.Type())
|
|
}
|
|
|
|
pair, found := h.Pairs[key.Hash()]
|
|
if !found {
|
|
return Null{}, nil
|
|
}
|
|
|
|
return pair.Value, nil
|
|
}
|
|
|
|
func (h *Hash) Set(index, other Object) error {
|
|
key, ok := index.(Hasher)
|
|
if !ok {
|
|
return fmt.Errorf("invalid hash key %s", index.Type())
|
|
}
|
|
|
|
h.Pairs[key.Hash()] = HashPair{Key: index, Value: other}
|
|
|
|
return nil
|
|
}
|
|
|
|
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.(Hasher)
|
|
right, ok := obj.Pairs[hashed.Hash()]
|
|
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
|
|
}
|