diff --git a/py/dict.go b/py/dict.go index 1c54a3be..dfc9bfc0 100644 --- a/py/dict.go +++ b/py/dict.go @@ -60,6 +60,36 @@ func init() { } return nil, ExceptionNewf(KeyError, "%v", args[0]) }, 0, "gets(key, default) -> If there is a val corresponding to key, return val, otherwise default") + + DictType.Dict["items"] = MustNewMethod("items", func(self Object, args Tuple) (Object, error) { + dict := self.(Dict) + o := make([]Object, 0, len(dict.keys)) + for _, item := range dict.items { + if item[0] != nil { + o = append(o, Tuple{item[0], item[1]}) + } + } + return NewIterator(o), nil + }, 0, "items() -> list of D's (key, value) pairs, as 2-tuples") + + DictType.Dict["get"] = MustNewMethod("get", func(self Object, args Tuple) (Object, error) { + var length = len(args) + switch { + case length == 0: + return nil, ExceptionNewf(TypeError, "%s expected at least 1 arguments, got %d", "items()", length) + case length > 2: + return nil, ExceptionNewf(TypeError, "%s expected at most 2 arguments, got %d", "items()", length) + } + dict := self.(Dict) + if res, ok := dict.keys[args[0]]; ok { + return dict.items[res][1], nil + } + + if length == 2 { + return args[1], nil + } + return None, nil + }, 0, "gets(key, default) -> If there is a val corresponding to key, return val, otherwise default") } // String to object dictionary @@ -67,21 +97,44 @@ func init() { // Used for variables etc where the keys can only be strings type StringDict map[string]Object +type Dict struct { + keys map[Object]int + items [][2]Object // key-value pair +} + // Type of this StringDict object func (o StringDict) Type() *Type { return StringDictType } +// Type of this Dict object +func (o Dict) Type() *Type { + return DictType +} + // Make a new dictionary func NewStringDict() StringDict { return make(StringDict) } +// Make a new dictionary +func NewDict() *Dict { + return &Dict{} +} + // Make a new dictionary with reservation for n entries func NewStringDictSized(n int) StringDict { return make(StringDict, n) } +// Make a new dictionary with reservation for n entries +func NewDictSized(n int) *Dict { + return &Dict{ + keys: make(map[Object]int, n), + items: make([][2]Object, n), + } +} + // Checks that obj is exactly a dictionary and returns an error if not func DictCheckExact(obj Object) (StringDict, error) { dict, ok := obj.(StringDict) @@ -91,12 +144,27 @@ func DictCheckExact(obj Object) (StringDict, error) { return dict, nil } +// Checks that obj is exactly a dictionary and returns an error if not +func _DictCheckExact(obj Object) (*Dict, error) { + dict, ok := obj.(Dict) + if !ok { + return nil, expectingDict + } + return &dict, nil +} + // Checks that obj is exactly a dictionary and returns an error if not func DictCheck(obj Object) (StringDict, error) { // FIXME should be checking subclasses return DictCheckExact(obj) } +// Checks that obj is exactly a dictionary and returns an error if not +func _DictCheck(obj Object) (*Dict, error) { + // FIXME should be checking subclasses + return _DictCheckExact(obj) +} + // Copy a dictionary func (d StringDict) Copy() StringDict { e := make(StringDict, len(d)) @@ -106,10 +174,26 @@ func (d StringDict) Copy() StringDict { return e } +// Copy a dictionary +func (d Dict) Copy() *Dict { + e := NewDictSized(len(d.keys)) + for k, v := range d.keys { + e.keys[k] = v + e.items[v][0] = d.items[v][0] + e.items[v][1] = d.items[v][1] + } + return e +} + func (a StringDict) M__str__() (Object, error) { return a.M__repr__() } + +func (a Dict) M__str__() (Object, error) { + return a.M__repr__() +} + func (a StringDict) M__repr__() (Object, error) { var out bytes.Buffer out.WriteRune('{') @@ -135,6 +219,33 @@ func (a StringDict) M__repr__() (Object, error) { return String(out.String()), nil } +func (a Dict) M__repr__() (Object, error) { + var out bytes.Buffer + out.WriteRune('{') + spacer := false + for _, item := range a.items { + if item[0] != nil { + if spacer { + out.WriteString(", ") + } + keyStr, err := ReprAsString(item[0]) + if err != nil { + return nil, err + } + valueStr, err := ReprAsString(item[1]) + if err != nil { + return nil, err + } + out.WriteString(keyStr) + out.WriteString(": ") + out.WriteString(valueStr) + spacer = true + } + } + out.WriteRune('}') + return String(out.String()), nil +} + // Returns a list of keys from the dict func (d StringDict) M__iter__() (Object, error) { o := make([]Object, 0, len(d)) @@ -144,6 +255,17 @@ func (d StringDict) M__iter__() (Object, error) { return NewIterator(o), nil } +// Returns a list of keys from the dict +func (d Dict) M__iter__() (Object, error) { + o := make([]Object, 0, len(d.keys)) + for _, item := range d.items { + if item[0] != nil { + o = append(o, item[0]) + } + } + return NewIterator(o), nil +} + func (d StringDict) M__getitem__(key Object) (Object, error) { str, ok := key.(String) if ok { @@ -155,6 +277,15 @@ func (d StringDict) M__getitem__(key Object) (Object, error) { return nil, ExceptionNewf(KeyError, "%v", key) } +func (d Dict) M__getitem__(key Object) (Object, error) { + // FIXME should be checking hash of Object + res, ok := d.keys[key] + if ok { + return d.items[res][1], nil + } + return nil, ExceptionNewf(KeyError, "%v", key) +} + func (d StringDict) M__setitem__(key, value Object) (Object, error) { str, ok := key.(String) if !ok { @@ -164,6 +295,13 @@ func (d StringDict) M__setitem__(key, value Object) (Object, error) { return None, nil } +func (d Dict) M__setitem__(key, value Object) (Object, error) { + // FIXME should be checking hash of Object + d.keys[key] = len(d.items) + d.items = append(d.items, [2]Object{key, value}) + return None, nil +} + func (a StringDict) M__eq__(other Object) (Object, error) { b, ok := other.(StringDict) if !ok { @@ -188,6 +326,41 @@ func (a StringDict) M__eq__(other Object) (Object, error) { return True, nil } +func (a Dict) M__eq__(other Object) (Object, error) { + b, ok := other.(Dict) + if !ok { + return NotImplemented, nil + } + if len(a.keys) != len(b.keys) { + return False, nil + } + for k, ai := range a.keys { + // FIXME should be checking hash of Object + bi, ok := b.keys[k] + if !ok || len(a.keys) < ai || len(b.keys) < bi { + return False, nil + } + aitem := a.items[ai] + bitem := b.items[bi] + + res, err := Eq(aitem[0], bitem[0]) + if err != nil { + return nil, err + } + if res == False { + return False, nil + } + res, err = Eq(aitem[1], bitem[1]) + if err != nil { + return nil, err + } + if res == False { + return False, nil + } + } + return True, nil +} + func (a StringDict) M__ne__(other Object) (Object, error) { res, err := a.M__eq__(other) if err != nil { @@ -202,6 +375,10 @@ func (a StringDict) M__ne__(other Object) (Object, error) { return True, nil } +func (a Dict) M__ne__(other Object) (Object, error) { + return notEq(a.M__eq__(other)) +} + func (a StringDict) M__contains__(other Object) (Object, error) { key, ok := other.(String) if !ok { @@ -213,3 +390,11 @@ func (a StringDict) M__contains__(other Object) (Object, error) { } return False, nil } + +func (a Dict) M__contains__(other Object) (Object, error) { + // FIXME should be checking hash of Object + if i, ok := a.keys[other]; ok { + return Eq(other, a.items[i][0]) + } + return False, nil +}
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: