refactor objects
This commit is contained in:
@@ -32,10 +32,24 @@ func (b Boolean) Inspect() string {
|
||||
return fmt.Sprintf("%t", b.Value)
|
||||
}
|
||||
|
||||
func (b Boolean) Clone() Object {
|
||||
// Copy implements the Copyable interface
|
||||
func (b Boolean) Copy() Object {
|
||||
return Boolean{Value: b.Value}
|
||||
}
|
||||
|
||||
// Hash implements the Hasher interface
|
||||
func (b Boolean) Hash() HashKey {
|
||||
var value uint64
|
||||
|
||||
if b.Value {
|
||||
value = 1
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
|
||||
return HashKey{Type: b.Type(), Value: value}
|
||||
}
|
||||
|
||||
func (b Boolean) String() string {
|
||||
return b.Inspect()
|
||||
}
|
||||
|
||||
@@ -4,24 +4,31 @@ import "unicode"
|
||||
|
||||
func NewEnclosedEnvironment(outer *Environment) *Environment {
|
||||
env := NewEnvironment()
|
||||
env.outer = outer
|
||||
env.parent = outer
|
||||
return env
|
||||
}
|
||||
|
||||
func NewEnvironment() *Environment {
|
||||
s := make(map[string]Object)
|
||||
return &Environment{store: s, outer: nil}
|
||||
return &Environment{store: s, parent: nil}
|
||||
}
|
||||
|
||||
type Environment struct {
|
||||
store map[string]Object
|
||||
outer *Environment
|
||||
store map[string]Object
|
||||
parent *Environment
|
||||
}
|
||||
|
||||
// New creates a new copy of the environment with the current environment as parent
|
||||
func (e *Environment) New() *Environment {
|
||||
env := NewEnvironment()
|
||||
env.parent = e
|
||||
return env
|
||||
}
|
||||
|
||||
func (e *Environment) Get(name string) (Object, bool) {
|
||||
obj, ok := e.store[name]
|
||||
if !ok && e.outer != nil {
|
||||
obj, ok = e.outer.Get(name)
|
||||
if !ok && e.parent != nil {
|
||||
obj, ok = e.parent.Get(name)
|
||||
}
|
||||
return obj, ok
|
||||
}
|
||||
@@ -40,7 +47,7 @@ func (e *Environment) ExportedHash() *Hash {
|
||||
for k, v := range e.store {
|
||||
if unicode.IsUpper(rune(k[0])) {
|
||||
s := String{Value: k}
|
||||
pairs[s.HashKey()] = HashPair{Key: s, Value: v}
|
||||
pairs[s.Hash()] = HashPair{Key: s, Value: v}
|
||||
}
|
||||
}
|
||||
return &Hash{Pairs: pairs}
|
||||
|
||||
@@ -18,7 +18,8 @@ func (e Error) Inspect() string {
|
||||
return "Error: " + e.Message
|
||||
}
|
||||
|
||||
func (e Error) Clone() Object {
|
||||
// Copy implements the Copyable interface
|
||||
func (e Error) Copy() Object {
|
||||
return Error{Message: e.Message}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package object
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -12,29 +11,6 @@ type HashKey struct {
|
||||
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
|
||||
@@ -91,12 +67,12 @@ func (h *Hash) Add(other Object) (Object, error) {
|
||||
}
|
||||
|
||||
func (h *Hash) Get(index Object) (Object, error) {
|
||||
key, ok := index.(Hashable)
|
||||
key, ok := index.(Hasher)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid hash key %s", index.Type())
|
||||
}
|
||||
|
||||
pair, found := h.Pairs[key.HashKey()]
|
||||
pair, found := h.Pairs[key.Hash()]
|
||||
if !found {
|
||||
return Null{}, nil
|
||||
}
|
||||
@@ -105,12 +81,12 @@ func (h *Hash) Get(index Object) (Object, error) {
|
||||
}
|
||||
|
||||
func (h *Hash) Set(index, other Object) error {
|
||||
key, ok := index.(Hashable)
|
||||
key, ok := index.(Hasher)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid hash key %s", index.Type())
|
||||
}
|
||||
|
||||
h.Pairs[key.HashKey()] = HashPair{Key: index, Value: other}
|
||||
h.Pairs[key.Hash()] = HashPair{Key: index, Value: other}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -122,8 +98,8 @@ func (h *Hash) Compare(other Object) int {
|
||||
}
|
||||
for _, pair := range h.Pairs {
|
||||
left := pair.Value
|
||||
hashed := left.(Hashable)
|
||||
right, ok := obj.Pairs[hashed.HashKey()]
|
||||
hashed := left.(Hasher)
|
||||
right, ok := obj.Pairs[hashed.Hash()]
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
|
||||
@@ -18,10 +18,15 @@ func (i Integer) Inspect() string {
|
||||
return fmt.Sprintf("%d", i.Value)
|
||||
}
|
||||
|
||||
func (i Integer) Clone() Object {
|
||||
func (i Integer) Copy() Object {
|
||||
return Integer{Value: i.Value}
|
||||
}
|
||||
|
||||
// Hash implements the Hasher interface
|
||||
func (i Integer) Hash() HashKey {
|
||||
return HashKey{Type: i.Type(), Value: uint64(i.Value)}
|
||||
}
|
||||
|
||||
func (i Integer) String() string {
|
||||
return i.Inspect()
|
||||
}
|
||||
|
||||
@@ -25,12 +25,12 @@ func (m Module) Inspect() string {
|
||||
}
|
||||
|
||||
func (m Module) Get(index Object) (Object, error) {
|
||||
key, ok := index.(Hashable)
|
||||
key, ok := index.(Hasher)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid module attribute %s", index.Type())
|
||||
}
|
||||
|
||||
attr, found := m.Attrs.(*Hash).Pairs[key.HashKey()]
|
||||
attr, found := m.Attrs.(*Hash).Pairs[key.Hash()]
|
||||
if !found {
|
||||
return Null{}, nil
|
||||
}
|
||||
|
||||
@@ -54,17 +54,14 @@ func (t Type) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
// Comparable is the interface for comparing two Object and their underlying
|
||||
// values. It is the responsibility of the caller (left) to check for types.
|
||||
// Returns `true` iif the types and values are identical, `false` otherwise.
|
||||
// Comparable is the interface for objects to implement suitable comparisons
|
||||
type Comparable interface {
|
||||
Compare(other Object) int
|
||||
}
|
||||
|
||||
// Immutable is the interface for all immutable objects which must implement
|
||||
// the Clone() method used by binding names to values.
|
||||
type Immutable interface {
|
||||
Clone() Object
|
||||
// Copyable is the interface for creating copies of objects
|
||||
type Copyable interface {
|
||||
Copy() Object
|
||||
}
|
||||
|
||||
// Object represents a value and implementations are expected to implement
|
||||
@@ -76,10 +73,9 @@ type Object interface {
|
||||
Inspect() string
|
||||
}
|
||||
|
||||
// Hashable is the interface for all hashable objects which must implement
|
||||
// the HashKey() method which returns a HashKey result.
|
||||
type Hashable interface {
|
||||
HashKey() HashKey
|
||||
// Hasher is the interface for objects to provide suitable hash keys
|
||||
type Hasher interface {
|
||||
Hash() HashKey
|
||||
}
|
||||
|
||||
// BuiltinFunction represents the builtin function type
|
||||
|
||||
@@ -8,15 +8,15 @@ func TestStringHashKey(t *testing.T) {
|
||||
diff1 := String{Value: "My name is johnny"}
|
||||
diff2 := String{Value: "My name is johnny"}
|
||||
|
||||
if hello1.HashKey() != hello2.HashKey() {
|
||||
if hello1.Hash() != hello2.Hash() {
|
||||
t.Errorf("string with same content have different hash keys")
|
||||
}
|
||||
|
||||
if diff1.HashKey() != diff2.HashKey() {
|
||||
if diff1.Hash() != diff2.Hash() {
|
||||
t.Errorf("string with same content have different hash keys")
|
||||
}
|
||||
|
||||
if hello1.HashKey() == diff1.HashKey() {
|
||||
if hello1.Hash() == diff1.Hash() {
|
||||
t.Errorf("string with different content have same hash keys")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
@@ -26,10 +27,18 @@ func (s String) Inspect() string {
|
||||
return fmt.Sprintf("%#v", s.Value)
|
||||
}
|
||||
|
||||
func (s String) Clone() Object {
|
||||
func (s String) Copy() Object {
|
||||
return String{Value: s.Value}
|
||||
}
|
||||
|
||||
// Hash implements the Hasher interface
|
||||
func (s String) Hash() HashKey {
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(s.Value))
|
||||
|
||||
return HashKey{Type: s.Type(), Value: h.Sum64()}
|
||||
}
|
||||
|
||||
func (s String) String() string {
|
||||
return s.Value
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user