Skip to content

Commit 25b128f

Browse files
committed
feat(dict): all meth except fromkeys,popitem; fix(py): dict() accepted no arg
1 parent d5e93e2 commit 25b128f

File tree

4 files changed

+102
-16
lines changed

4 files changed

+102
-16
lines changed

Objects/dictobject.nim

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ declarePyType Dict(tpToken, reprLock, mutable):
1919
table: Table[PyObject, PyObject]
2020

2121

22-
proc newPyDict* : PyDictObject =
22+
proc newPyDict*(table=initTable[PyObject, PyObject]()) : PyDictObject =
2323
result = newPyDictSimple()
24-
result.table = initTable[PyObject, PyObject]()
24+
result.table = table
2525

26-
proc hasKey*(dict: PyDictObject, key: PyObject): bool =
26+
proc hasKey*(dict: PyDictObject, key: PyObject): bool =
2727
return dict.table.hasKey(key)
2828
proc contains*(dict: PyDictObject, key: PyObject): bool = dict.hasKey key
2929

@@ -101,15 +101,16 @@ implDictMagic len, [mutable: read]:
101101
newPyInt(self.table.len)
102102

103103
implDictMagic hash: unhashable self
104-
105-
implDictMagic New:
106-
newPyDict()
107-
108104
implDictMagic eq:
109105
newPyBool(
110106
other.ofPyDictObject() and
111107
self.table == other.PyDictObject.table
112108
)
109+
implDictMagic Or(E: PyDictObject), [mutable: read]:
110+
let res = newPyDict self.table
111+
for (k, v) in E.table.pairs:
112+
res.table[k] = v
113+
res
113114

114115
template keyError(other: PyObject): PyObject =
115116
var msg: PyStrObject
@@ -175,7 +176,6 @@ implDictMethod get, [mutable: write]:
175176
let defval = args[1]
176177
result.handleBadHash:
177178
return self.table.getOrDefault(key, defVal)
178-
# XXX: Python's dict.get(k, v) doesn't discard TypeError
179179

180180
implDictMethod pop, [mutable: write]:
181181
checkargnumatleast 1
@@ -190,6 +190,21 @@ implDictMethod pop, [mutable: write]:
190190
# XXX: Python's dict.pop(k, v) discard TypeError, KeyError
191191
return defval
192192

193+
implDictMethod setdefault, [mutable: write]:
194+
checkargnumatleast 1
195+
let key = args[0]
196+
checkhashabletmpl(key)
197+
let defVal = if args.len == 1: pyNone
198+
else:
199+
checkargnum 2
200+
args[1]
201+
202+
result.handleBadHash:
203+
if key in self:
204+
return self[key]
205+
self[key] = defVal
206+
return defval
207+
193208
implDictMethod clear(), [mutable: write]: self.clear()
194209

195210
implDictMethod copy(), [mutable: read]:
@@ -204,3 +219,5 @@ implDictMethod copy(), [mutable: read]:
204219
proc update*(d1, d2: PyDictObject) =
205220
for k, v in d2.table.pairs:
206221
d1[k] = v
222+
223+
# .__init__, .update, .keys, etc method is defined in ./dictobjectImpl

Objects/dictobjectImpl.nim

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
2+
3+
import ./pyobject
4+
import ../Python/call
5+
import ./[stringobject, iterobject, numobjects]
6+
import ./noneobject
7+
import ./exceptions
8+
import ./dictobject
9+
export dictobject
10+
11+
12+
# redeclare this for these are "private" macros
13+
14+
methodMacroTmpl(Dict)
15+
16+
17+
18+
19+
proc updateImpl*(self: PyDictObject, E: PyObject): PyObject =
20+
if E.ofPyDictObject:
21+
self.update PyDictObject E
22+
return pyNone
23+
let
24+
keysFunc = E.callMagic(getattr, newPyAscii"keys") # getattr(E, "keys")
25+
getitem = E.getMagic(getitem)
26+
if not keysFunc.isThrownException and not getitem.isNil:
27+
let ret = fastCall(keysFunc, @[])
28+
if ret.isThrownException: return ret
29+
pyForIn i, ret:
30+
self[i] = getitem(E, i)
31+
else:
32+
var idx = 0
33+
pyForIn ele, E:
34+
let getter = ele.getMagic(getitem)
35+
if getter.isNil:
36+
return newTypeError newPyAscii(
37+
"cannot convert dictionary update sequence element #" &
38+
$idx & " to a sequence")
39+
# only use getitem
40+
let
41+
k = getter(ele, pyIntZero)
42+
v = getter(ele, pyIntOne)
43+
self[k] = v
44+
idx.inc
45+
pyNone
46+
47+
implDictMagic iOr(E: PyObject), [mutable: write]: self.updateImpl E
48+
49+
# XXX: how to impl using std/table?
50+
# implDictMethod popitem(), [mutable: write]:
51+
52+
implDictMethod update(E: PyObject), [mutable: write]:
53+
# XXX: `**kw` not supported in syntax
54+
self.updateImpl E
55+
56+
implDictMagic init:
57+
let argsLen = args.len
58+
case argsLen
59+
of 0: pyNone
60+
of 1:
61+
let ret = self.updateImpl(args[argsLen-1])
62+
if ret.isThrownException: return ret
63+
pyNone
64+
else:
65+
errArgNum argsLen, 1

Objects/exceptions.nim

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,16 +195,20 @@ template getIterableWithCheck*(obj: PyObject): (PyObject, UnaryMethod) =
195195
retTuple = (iterobj, iternextFunc)
196196
retTuple
197197

198+
template errArgNum*(argsLen, expected: int; name="")=
199+
bind fmt, newTypeError, newPyStr
200+
var msg: string
201+
let sargsLen{.inject.} = $argsLen
202+
if name != "":
203+
msg = name & " takes exactly " & $expected & fmt" argument ({sargsLen} given)"
204+
else:
205+
msg = "expected " & $expected & fmt" argument ({sargsLen} given)"
206+
return newTypeError(newPyStr msg)
198207

199208
template checkArgNum*(expected: int, name="") =
200-
bind fmt, newTypeError, newPyStr
209+
bind errArgNum
201210
if args.len != expected:
202-
var msg: string
203-
if name != "":
204-
msg = name & " takes exactly " & $expected & fmt" argument ({args.len} given)"
205-
else:
206-
msg = "expected " & $expected & fmt" argument ({args.len} given)"
207-
return newTypeError(newPyStr msg)
211+
errArgNum args.len, expected, name
208212

209213

210214
template checkArgNumAtLeast*(expected: int, name="") =

Python/bltinmodule.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import strformat
33
import neval
44
import builtindict
55
import ../Objects/[bundle, typeobject, methodobject, descrobject, funcobject,
6-
notimplementedobject, sliceobjectImpl, exceptions]
6+
notimplementedobject, sliceobjectImpl, dictobjectImpl, exceptions]
77
import ../Utils/[utils, macroutils, compat]
88

99

0 commit comments

Comments
 (0)