aboutsummaryrefslogtreecommitdiff
path: root/object
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2017-05-20 16:28:10 +0200
committerDimitri Sokolyuk <demon@dim13.org>2017-05-20 16:28:10 +0200
commit523f40968b9c1a23da1f4a1c2f125197d7611fef (patch)
tree36518bed0260cb3cede13b59fc7051a9e262d403 /object
parent69fc902f8f5fd8f36db0991f6ba4faeabb3090fa (diff)
04
Diffstat (limited to 'object')
-rw-r--r--object/object.go97
-rw-r--r--object/object_test.go60
2 files changed, 157 insertions, 0 deletions
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")
+ }
+}