forked from go-python/gpython
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dict.go
156 lines (138 loc) · 3.42 KB
/
dict.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright 2018 The go-python Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Dict and StringDict type
//
// The idea is that most dicts just have strings for keys so we use
// the simpler StringDict and promote it into a Dict when necessary
package py
import "bytes"
const dictDoc = `dict() -> new empty dictionary
dict(mapping) -> new dictionary initialized from a mapping object's
(key, value) pairs
dict(iterable) -> new dictionary initialized as if via:
d = {}
for k, v in iterable:
d[k] = v
dict(**kwargs) -> new dictionary initialized with the name=value pairs
in the keyword argument list. For example: dict(one=1, two=2)`
var (
StringDictType = NewType("dict", dictDoc)
DictType = NewType("dict", dictDoc)
expectingDict = ExceptionNewf(TypeError, "a dict is required")
)
// String to object dictionary
//
// Used for variables etc where the keys can only be strings
type StringDict map[string]Object
// Type of this StringDict object
func (o StringDict) Type() *Type {
return StringDictType
}
// Make a new dictionary
func NewStringDict() StringDict {
return make(StringDict)
}
// Make a new dictionary with reservation for n entries
func NewStringDictSized(n int) StringDict {
return make(StringDict, n)
}
// Checks that obj is exactly a dictionary and returns an error if not
func DictCheckExact(obj Object) (StringDict, error) {
dict, ok := obj.(StringDict)
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)
}
// Copy a dictionary
func (d StringDict) Copy() StringDict {
e := make(StringDict, len(d))
for k, v := range d {
e[k] = v
}
return e
}
func (a StringDict) M__str__() (Object, error) {
return a.M__repr__()
}
func (a StringDict) M__repr__() (Object, error) {
var out bytes.Buffer
out.WriteRune('{')
spacer := false
for key, value := range a {
if spacer {
out.WriteString(", ")
}
keyStr, err := ReprAsString(String(key))
if err != nil {
return nil, err
}
valueStr, err := ReprAsString(value)
if err != nil {
return nil, err
}
out.WriteString(keyStr)
out.WriteString(": ")
out.WriteString(valueStr)
spacer = true
}
out.WriteRune('}')
return String(out.String()), nil
}
func (d StringDict) M__getitem__(key Object) (Object, error) {
str, ok := key.(String)
if ok {
res, ok := d[string(str)]
if ok {
return res, nil
}
}
return nil, ExceptionNewf(KeyError, "%v", key)
}
func (d StringDict) M__setitem__(key, value Object) (Object, error) {
str, ok := key.(String)
if !ok {
return nil, ExceptionNewf(KeyError, "FIXME can only have string keys!: %v", key)
}
d[string(str)] = value
return None, nil
}
func (a StringDict) M__eq__(other Object) (Object, error) {
b, ok := other.(StringDict)
if !ok {
return NotImplemented, nil
}
if len(a) != len(b) {
return False, nil
}
for k, av := range a {
bv, ok := b[k]
if !ok {
return False, nil
}
res, err := Eq(av, bv)
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 {
return nil, err
}
if res == True {
return False, nil
}
return True, nil
}