From 523f40968b9c1a23da1f4a1c2f125197d7611fef Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 20 May 2017 16:28:10 +0200 Subject: 04 --- object/object.go | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ object/object_test.go | 60 +++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 object/object_test.go (limited to 'object') diff --git a/object/object.go b/object/object.go index cdde084..2c2a1b0 100644 --- a/object/object.go +++ b/object/object.go @@ -3,10 +3,13 @@ package object import ( "bytes" "fmt" + "hash/fnv" "monkey/ast" "strings" ) +type BuiltinFunction func(args ...Object) Object + type ObjectType string const ( @@ -15,12 +18,26 @@ const ( INTEGER_OBJ = "INTEGER" BOOLEAN_OBJ = "BOOLEAN" + STRING_OBJ = "STRING" RETURN_VALUE_OBJ = "RETURN_VALUE" FUNCTION_OBJ = "FUNCTION" + BUILTIN_OBJ = "BUILTIN" + + ARRAY_OBJ = "ARRAY" + HASH_OBJ = "HASH" ) +type HashKey struct { + Type ObjectType + Value uint64 +} + +type Hashable interface { + HashKey() HashKey +} + type Object interface { Type() ObjectType Inspect() string @@ -32,6 +49,9 @@ type Integer struct { func (i *Integer) Type() ObjectType { return INTEGER_OBJ } func (i *Integer) Inspect() string { return fmt.Sprintf("%d", i.Value) } +func (i *Integer) HashKey() HashKey { + return HashKey{Type: i.Type(), Value: uint64(i.Value)} +} type Boolean struct { Value bool @@ -39,6 +59,17 @@ type Boolean struct { func (b *Boolean) Type() ObjectType { return BOOLEAN_OBJ } func (b *Boolean) Inspect() string { return fmt.Sprintf("%t", b.Value) } +func (b *Boolean) HashKey() HashKey { + var value uint64 + + if b.Value { + value = 1 + } else { + value = 0 + } + + return HashKey{Type: b.Type(), Value: value} +} type Null struct{} @@ -83,3 +114,69 @@ func (f *Function) Inspect() string { return out.String() } + +type String struct { + Value string +} + +func (s *String) Type() ObjectType { return STRING_OBJ } +func (s *String) Inspect() string { return s.Value } +func (s *String) HashKey() HashKey { + h := fnv.New64a() + h.Write([]byte(s.Value)) + + return HashKey{Type: s.Type(), Value: h.Sum64()} +} + +type Builtin struct { + Fn BuiltinFunction +} + +func (b *Builtin) Type() ObjectType { return BUILTIN_OBJ } +func (b *Builtin) Inspect() string { return "builtin function" } + +type Array struct { + Elements []Object +} + +func (ao *Array) Type() ObjectType { return ARRAY_OBJ } +func (ao *Array) Inspect() string { + var out bytes.Buffer + + elements := []string{} + for _, e := range ao.Elements { + elements = append(elements, e.Inspect()) + } + + out.WriteString("[") + out.WriteString(strings.Join(elements, ", ")) + out.WriteString("]") + + return out.String() +} + +type HashPair struct { + Key Object + Value Object +} + +type Hash struct { + Pairs map[HashKey]HashPair +} + +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() +} diff --git a/object/object_test.go b/object/object_test.go new file mode 100644 index 0000000..63228a2 --- /dev/null +++ b/object/object_test.go @@ -0,0 +1,60 @@ +package object + +import "testing" + +func TestStringHashKey(t *testing.T) { + hello1 := &String{Value: "Hello World"} + hello2 := &String{Value: "Hello World"} + diff1 := &String{Value: "My name is johnny"} + diff2 := &String{Value: "My name is johnny"} + + if hello1.HashKey() != hello2.HashKey() { + t.Errorf("strings with same content have different hash keys") + } + + if diff1.HashKey() != diff2.HashKey() { + t.Errorf("strings with same content have different hash keys") + } + + if hello1.HashKey() == diff1.HashKey() { + t.Errorf("strings with different content have same hash keys") + } +} + +func TestBooleanHashKey(t *testing.T) { + true1 := &Boolean{Value: true} + true2 := &Boolean{Value: true} + false1 := &Boolean{Value: false} + false2 := &Boolean{Value: false} + + if true1.HashKey() != true2.HashKey() { + t.Errorf("trues do not have same hash key") + } + + if false1.HashKey() != false2.HashKey() { + t.Errorf("falses do not have same hash key") + } + + if true1.HashKey() == false1.HashKey() { + t.Errorf("true has same hash key as false") + } +} + +func TestIntegerHashKey(t *testing.T) { + one1 := &Integer{Value: 1} + one2 := &Integer{Value: 1} + two1 := &Integer{Value: 2} + two2 := &Integer{Value: 2} + + if one1.HashKey() != one2.HashKey() { + t.Errorf("integers with same content have twoerent hash keys") + } + + if two1.HashKey() != two2.HashKey() { + t.Errorf("integers with same content have twoerent hash keys") + } + + if one1.HashKey() == two1.HashKey() { + t.Errorf("integers with twoerent content have same hash keys") + } +} -- cgit v1.2.3