Skip to content
Permalink
Newer
Older
100644 1243 lines (1123 sloc) 36.4 KB
Sep 5, 2014
1
;(function($B){
2
3
/*
4
Implementation of Python dictionaries
5
6
We can't use Javascript's Map here, because the behaviour is not exactly the
7
same (eg with keys that are instances of classes with a __hash__ method...)
8
and because Map is much slower than regular Javascript objects.
9
10
A Python dictionary is implemented as a Javascript objects with these
11
attributes:
12
. $version: an integer with an initial value of 0, incremented at each
13
insertion
14
. $numeric_dict: for keys of type int
15
. $string_dict and $str_hash: for keys of type str
16
. $object_dict: for keys of other types
17
18
The value associated to a key in $numeric_dict and $string_dict is a pair
19
[value, rank] where "value" is the value associated with the key and "rank"
20
is the value of the dict attribute $version when the pair is inserted. This
21
is required to keep track of the insertion order, mandatory since Python 3.7.
22
23
For keys that are not str or int, their hash value is computed. Since several
24
keys with the same hash can be stored in a dictionary, $object_dict[hash] is a
25
list of [key, [value, rank]] lists.
26
*/
27
28
var _b_ = $B.builtins
30
var str_hash = _b_.str.__hash__,
Sep 5, 2014
32
33
var set_ops = ["eq", "le", "lt", "ge", "gt",
34
"sub", "rsub", "and", "or", "xor"]
35
36
// methods to compare non set-like views
37
function is_sublist(t1, t2){
38
// Return true if all elements of t1 are in t2
39
for(var i = 0, ilen = t1.length; i < ilen; i++){
40
var x = t1[i],
41
flag = false
42
for(var j = 0, jlen = t2.length; j < jlen; j++){
43
if($B.rich_comp("__eq__", x, t2[j])){
44
t2.splice(j, 1)
45
flag = true
46
break
47
}
48
}
49
if(! flag){
50
return false
51
}
52
}
53
return true
54
}
55
56
dict_view_op = {
57
__eq__: function(t1, t2){
58
return t1.length == t2.length && is_sublist(t1, t2)
59
},
60
__ne__: function(t1, t2){
61
return ! dict_view_op.__eq__(t1, t2)
62
},
63
__lt__: function(t1, t2){
64
return t1.length < t2.length && is_sublist(t1, t2)
65
},
66
__gt__: function(t1, t2){
67
return dict_view_op.__lt__(t2, t1)
68
},
69
__le__: function(t1, t2){
70
return t1.length <= t2.length && is_sublist(t1, t2)
71
},
72
__ge__: function(t1, t2){
73
return dict_view_op.__le__(t2, t1)
74
},
75
__and__: function(t1, t2){
76
var items = []
77
for(var i = 0, ilen = t1.length; i < ilen; i++){
78
var x = t1[i]
79
flag = false
80
for(var j = 0, jlen = t2.length; j < jlen; j++){
81
if($B.rich_comp("__eq__", x, t2[j])){
82
t2.splice(j, 1)
83
items.push(x)
84
break
85
}
86
}
87
}
88
return items
89
},
90
__or__: function(t1, t2){
91
var items = t1
92
for(var j = 0, jlen = t2.length; j < jlen; j++){
93
var y = t2[j],
94
flag = false
95
for(var i = 0, ilen = t1.length; i < ilen; i++){
96
if($B.rich_comp("__eq__", y, t1[i])){
97
t2.splice(j, 1)
98
flag = true
99
break
100
}
101
}
102
if(! flag){
103
items.push(y)
104
}
105
}
106
return items
107
}
109
}
110
111
$B.make_view = function(name){
112
var klass = $B.make_class(name, function(d, items, set_like){
113
return {
114
__class__: klass,
119
len: items.length,
120
set_like: set_like
124
for(var i = 0, len = set_ops.length; i < len; i++){
125
var op = "__" + set_ops[i] + "__"
126
klass[op] = (function(op){
127
return function(self, other){
128
// compare set of items to other
129
if(self.set_like){
130
return _b_.set[op](_b_.set.$factory(self),
131
_b_.set.$factory(other))
132
}else{
133
// Non-set like views can only be compared to
134
// instances of the same class
135
if(other.__class__ !== klass){
136
return false
138
var other_items = _b_.list.$factory(other)
139
return dict_view_op[op](self.items, other_items)
145
klass.__iter__ = function(self){
146
var it = klass.$iterator.$factory(self.items)
147
it.test_change = function(){
148
return self.dict.$version != self.dict_version
149
}
152
153
klass.__len__ = function(self){
154
return self.len
155
}
157
klass.__repr__ = function(self){
158
return klass.$infos.__name__ + '(' + _b_.repr(self.items) + ')'
159
}
160
161
$B.set_func_names(klass, "builtins")
Feb 11, 2018
165
var dict = {
Feb 11, 2018
166
__class__: _b_.type,
168
$infos: {
169
__module__: "builtins",
170
__name__: "dict"
171
},
Feb 11, 2018
172
$is_class: true,
173
$native: true,
174
$match_mapping_pattern: true // for pattern matching (PEP 634)
Sep 5, 2014
175
}
176
177
dict.$to_obj = function(d){
178
// Function applied to dictionary that only have string keys,
179
// return a Javascript objects with the kays mapped to the value,
180
// excluding the insertion rank
181
var res = {}
182
for(var key in d.$string_dict){
183
res[key] = d.$string_dict[key][0]
184
}
185
return res
186
}
187
188
function to_list(d, ix){
189
var items = [],
190
item
192
if(d.$jsobj){
Mar 7, 2018
195
if(attr.charAt(0) != "$"){
196
var val = d.$jsobj[attr]
197
if(val === undefined){val = _b_.NotImplemented}
198
else if(val === null){val = $N}
202
}else if(_b_.isinstance(d, _b_.dict)){
203
for(var k in d.$numeric_dict){
204
items.push([parseFloat(k), d.$numeric_dict[k]])
205
}
207
for(var k in d.$string_dict){
208
items.push([k, d.$string_dict[k]])
209
}
211
for(var k in d.$object_dict){
212
d.$object_dict[k].forEach(function(item){
213
items.push(item)
214
})
215
}
217
// sort by insertion order
218
items.sort(function(a, b){
219
return a[1][1] - b[1][1]
220
})
221
items = items.map(function(item){return [item[0], item[1][0]]})
224
res = items.map(function(item){return item[ix]})
225
return res
226
}else{
227
items.__class__ = _b_.tuple
228
return items.map(function(item){
229
item.__class__ = _b_.tuple; return item}
230
)
231
}
Feb 9, 2015
233
234
$B.dict_to_list = to_list // used in py_types.js
235
236
var $copy_dict = function(left, right){
238
si = dict.$setitem
239
right.$version = right.$version || 0
240
var right_version = right.$version || 0
241
for(var i = 0, len = _l.length; i < len; i++){
242
si(left, _l[i][0], _l[i][1])
243
if(right.$version != right_version){
244
throw _b_.RuntimeError.$factory("dict mutated during update")
245
}
246
}
249
function rank(self, hash, key){
250
// Search if object key, with hash = hash(key), is in
251
// self.$object_dict
252
var pairs = self.$object_dict[hash]
253
if(pairs !== undefined){
254
for(var i = 0, len = pairs.length; i < len; i++){
255
if($B.rich_comp("__eq__", key, pairs[i][0])){
256
return i
257
}
258
}
259
}
260
return -1
261
}
262
Feb 11, 2018
263
dict.__bool__ = function () {
Mar 7, 2018
264
var $ = $B.args("__bool__", 1, {self: null}, ["self"],
265
arguments, {}, null, null)
Feb 11, 2018
266
return dict.__len__($.self) > 0
269
dict.__class_getitem__ = function(cls, item){
270
// PEP 585
271
// Set as a classmethod at the end of this script, after $B.set_func_names()
272
if(! Array.isArray(item)){
273
item = [item]
274
}
275
return $B.GenericAlias.$factory(cls, item)
276
}
277
Feb 11, 2018
278
dict.__contains__ = function(){
279
var $ = $B.args("__contains__", 2, {self: null, key: null},
280
["self", "key"], arguments, {}, null, null),
281
self = $.self,
284
if(self.$jsobj){
285
return self.$jsobj[key] !== undefined
286
}
288
switch(typeof key) {
290
return self.$string_dict[key] !== undefined
292
return self.$numeric_dict[key] !== undefined
293
}
294
295
var hash = _b_.hash(key)
296
if(self.$str_hash[hash] !== undefined &&
297
$B.rich_comp("__eq__", key, self.$str_hash[hash])){
298
return true
299
}
300
if(self.$numeric_dict[hash] !== undefined &&
301
$B.rich_comp("__eq__", key, hash)){
302
return true
303
}
304
return rank(self, hash, key) > -1
Sep 5, 2014
305
}
306
Feb 11, 2018
307
dict.__delitem__ = function(){
Nov 21, 2015
308
309
var $ = $B.args("__eq__", 2, {self: null, arg: null},
310
["self", "arg"], arguments, {}, null, null),
311
self = $.self,
Nov 21, 2015
313
314
if(self.$jsobj){
315
if(self.$jsobj[arg] === undefined){throw _b_.KeyError.$factory(arg)}
316
delete self.$jsobj[arg]
319
switch(typeof arg){
320
case "string":
321
if(self.$string_dict[arg] === undefined){
322
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
323
}
324
delete self.$string_dict[arg]
325
delete self.$str_hash[str_hash(arg)]
327
return $N
328
case "number":
329
if(self.$numeric_dict[arg] === undefined){
330
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
332
delete self.$numeric_dict[arg]
336
// go with defaults
337
338
var hash = _b_.hash(arg),
339
ix
341
if((ix = rank(self, hash, arg)) > -1){
342
self.$object_dict[hash].splice(ix, 1)
343
}else{
344
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
Sep 5, 2014
349
}
350
Feb 11, 2018
351
dict.__eq__ = function(){
Mar 7, 2018
352
var $ = $B.args("__eq__", 2, {self: null, other: null},
353
["self", "other"], arguments, {}, null, null),
354
self = $.self,
355
other = $.other
357
if(! _b_.isinstance(other, dict)){return false}
359
if(self.$jsobj){self = jsobj2dict(self.$jsobj)}
360
if(other.$jsobj){other = jsobj2dict(other.$jsobj)}
361
if(dict.__len__(self) != dict.__len__(other)){
362
return false
363
}
365
if(self.$string_dict.length != other.$string_dict.length){
369
for(var k in self.$numeric_dict){
370
if(other.$numeric_dict.hasOwnProperty(k)){
371
if(!$B.rich_comp("__eq__", other.$numeric_dict[k][0],
372
self.$numeric_dict[k][0])){
373
return false
374
}
375
}else if(other.$object_dict.hasOwnProperty(k)){
376
var pairs = other.$object_dict[k],
377
flag = false
378
for(var i = 0, len = pairs.length; i < len; i++){
379
if($B.rich_comp("__eq__", k, pairs[i][0]) &&
380
$B.rich_comp("__eq__", self.$numeric_dict[k],
381
pairs[i][1])){
382
flag = true
383
break
384
}
386
if(! flag){return false}
Nov 21, 2015
389
}
390
}
391
for(var k in self.$string_dict){
392
if(!other.$string_dict.hasOwnProperty(k) ||
393
!$B.rich_comp("__eq__", other.$string_dict[k][0],
394
self.$string_dict[k][0])){
Nov 21, 2015
396
}
397
}
398
for(var hash in self.$object_dict){
399
var pairs = self.$object_dict[hash]
400
// Get all (key, value) pairs in other that have the same hash
401
var other_pairs = []
402
if(other.$numeric_dict[hash] !== undefined){
403
other_pairs.push([hash, other.$numeric_dict[hash]])
404
}
405
if(other.$object_dict[hash] !== undefined){
406
other_pairs = other_pairs.concat(other.$object_dict[hash])
407
}
408
if(other_pairs.length == 0){
409
return false
410
}
411
for(var i = 0, len_i = pairs.length; i < len_i; i++){
412
var flag = false
413
var key = pairs[i][0],
414
value = pairs[i][1][0]
415
for(var j = 0, len_j = other_pairs.length; j < len_j; j++){
416
if($B.rich_comp("__eq__", key, other_pairs[j][0]) &&
417
$B.rich_comp("__eq__", value, other_pairs[j][1][0])){
418
flag = true
419
break
425
}
426
}
427
return true
Sep 5, 2014
428
}
429
Feb 11, 2018
430
dict.__getitem__ = function(){
431
var $ = $B.args("__getitem__", 2, {self: null, arg: null},
432
["self", "arg"], arguments, {}, null, null),
433
self = $.self,
435
return dict.$getitem(self, arg)
436
}
437
438
dict.$getitem = function(self, arg, ignore_missing){
439
// ignore_missing is set in dict.get and dict.setdefault
440
if(self.$jsobj){
441
if(self.$jsobj[arg] === undefined){
442
if(self.$jsobj.hasOwnProperty &&
443
self.$jsobj.hasOwnProperty(arg)){
445
}
446
throw _b_.KeyError.$factory(arg)
447
}
448
return self.$jsobj[arg]
450
451
switch(typeof arg){
452
case "string":
453
var x = self.$string_dict[arg]
454
if(x !== undefined){
455
return x[0]
457
break
458
case "number":
459
if(self.$numeric_dict[arg] !== undefined){
460
return self.$numeric_dict[arg][0]
462
break
463
}
464
465
// since the key is more complex use 'default' method of getting item
466
467
var hash = _b_.hash(arg),
468
_eq = function(other){return $B.rich_comp("__eq__", arg, other)}
469
470
if(typeof arg == "object"){
471
arg.$hash = hash // cache for setdefault
472
}
473
var sk = self.$str_hash[hash]
474
if(sk !== undefined && _eq(sk)){
475
return self.$string_dict[sk][0]
477
if(self.$numeric_dict[hash] !== undefined && _eq(hash)){
478
return self.$numeric_dict[hash][0]
480
if(_b_.isinstance(arg, _b_.str)){
481
// string subclass
482
var res = self.$string_dict[arg.valueOf()]
483
if(res !== undefined){return res[0]}
486
var ix = rank(self, hash, arg)
487
if(ix > -1){
488
return self.$object_dict[hash][ix][1][0]
491
if(! ignore_missing){
492
if(self.__class__ !== dict && ! ignore_missing){
493
try{
494
var missing_method = $B.$getattr(self.__class__,
495
"__missing__", _b_.None)
496
}catch(err){
497
console.log(err)
499
}
500
if(missing_method !== _b_.None){
501
return missing_method(self, arg)
502
}
505
throw _b_.KeyError.$factory(arg)
Sep 5, 2014
506
}
507
508
dict.__hash__ = _b_.None
Sep 5, 2014
509
510
function init_from_list(self, args){
511
var i = -1,
512
stop = args.length - 1,
513
si = dict.__setitem__
514
while(i++ < stop){
515
var item = args[i]
516
if(item.length != 2){
517
throw _b_.ValueError.$factory("dictionary " +
518
`update sequence element #${i} has length 1; 2 is required`)
519
}
520
switch(typeof item[0]) {
521
case 'string':
522
self.$string_dict[item[0]] = [item[1], self.$order++]
523
self.$str_hash[str_hash(item[0])] = item[0]
524
self.$version++
525
break
526
case 'number':
527
if(item[0] != 0 && item[0] != 1){
528
self.$numeric_dict[item[0]] = [item[1], self.$order++]
529
self.$version++
530
break
531
}
532
default:
533
si(self, item[0], item[1])
534
break
535
}
536
}
537
}
538
539
dict.__init__ = function(self, first, second){
540
if(first === undefined){
541
return $N
542
}
544
if(first.$nat != 'kw' && $B.get_class(first) === $B.JSObj){
545
for(var key in first){
546
self.$string_dict[key] = [first[key], self.$order++]
547
}
548
return _b_.None
549
}else if(first.$jsobj){
550
self.$jsobj = {}
551
for(var attr in first.$jsobj){
552
self.$jsobj[attr] = first.$jsobj[attr]
555
}else if(Array.isArray(first)){
556
init_from_list(self, first)
557
return $N
Sep 5, 2014
558
}
561
var $ = $B.args("dict", 1, {self:null}, ["self"],
562
arguments, {}, "first", "second")
563
var args = $.first
564
if(args.length > 1){
565
throw _b_.TypeError.$factory("dict expected at most 1 argument" +
566
", got 2")
567
}else if(args.length == 1){
568
args = args[0]
569
if(args.__class__ === dict){
570
['$string_dict', '$str_hash', '$numeric_dict', '$object_dict'].
571
forEach(function(d){
572
for(key in args[d]){self[d][key] = args[d][key]}
573
})
574
}else if(_b_.isinstance(args, dict)){
577
var keys = $B.$getattr(args, "keys", null)
578
if(keys !== null){
579
var gi = $B.$getattr(args, "__getitem__", null)
580
if(gi !== null){
581
// has keys and __getitem__ : it's a mapping, iterate on
582
// keys and values
583
gi = $B.$call(gi)
584
var kiter = _b_.iter($B.$call(keys)())
585
while(true){
586
try{
587
var key = _b_.next(kiter),
588
value = gi(key)
589
dict.__setitem__(self, key, value)
590
}catch(err){
591
if(err.__class__ === _b_.StopIteration){
592
break
593
}
594
throw err
595
}
596
}
597
return $N
598
}
599
}
600
if(! Array.isArray(args)){
601
args = _b_.list.$factory(args)
602
}
603
// Form "dict([[key1, value1], [key2,value2], ...])"
604
init_from_list(self, args)
Sep 5, 2014
605
}
607
var kw = $.second.$string_dict
608
for(var attr in kw){
609
switch(typeof attr){
610
case "string":
611
self.$string_dict[attr] = [kw[attr][0], self.$order++]
612
self.$str_hash[str_hash(attr)] = attr
613
break
614
case "number":
615
self.$numeric_dict[attr] = [kw[attr][0], self.$order++]
618
si(self, attr, kw[attr][0])
Sep 5, 2014
623
}
624
625
dict.__iter__ = function(self){
626
return _b_.iter(dict.keys(self))
Sep 5, 2014
627
}
628
629
dict.__ior__ = function(self, other){
630
// PEP 584
631
dict.update(self, other)
632
return self
633
}
634
Feb 11, 2018
635
dict.__len__ = function(self) {
638
if(self.$jsobj){
Mar 7, 2018
639
for(var attr in self.$jsobj){if(attr.charAt(0) != "$"){_count++}}
640
return _count
641
}
643
for(var k in self.$numeric_dict){_count++}
644
for(var k in self.$string_dict){_count++}
645
for(var hash in self.$object_dict){
646
_count += self.$object_dict[hash].length
647
}
Sep 5, 2014
651
Mar 7, 2018
652
dict.__ne__ = function(self, other){return ! dict.__eq__(self, other)}
Sep 5, 2014
653
Feb 11, 2018
654
dict.__new__ = function(cls){
655
if(cls === undefined){
Mar 7, 2018
656
throw _b_.TypeError.$factory("int.__new__(): not enough arguments")
658
var instance = {
660
$numeric_dict : {},
661
$object_dict : {},
664
$version: 0,
665
$order: 0
667
if(cls !== dict){
668
instance.__dict__ = $B.empty_dict()
669
}
670
return instance
673
dict.__or__ = function(self, other){
674
// PEP 584
675
if(! _b_.isinstance(other, dict)){
676
return _b_.NotImplemented
677
}
678
var res = dict.copy(self)
679
dict.update(res, other)
680
return res
681
}
682
683
function __newobj__(){
684
// __newobj__ is called with a generator as only argument
685
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
686
args = $.args
687
var res = $B.empty_dict()
688
res.__class__ = args[0]
689
return res
690
}
691
692
dict.__reduce_ex__ = function(self, protocol){
693
return $B.fast_tuple([
694
__newobj__,
695
$B.fast_tuple([self.__class__]),
696
_b_.None,
697
_b_.None,
698
dict.items(self)])
699
}
700
Feb 11, 2018
701
dict.__repr__ = function(self){
702
$B.builtins_repr_check(dict, arguments) // in brython_builtins.js
703
if(self.$jsobj){ // wrapper around Javascript object
Feb 11, 2018
704
return dict.__repr__(jsobj2dict(self.$jsobj))
706
if($B.repr.enter(self)){
707
return "{...}"
708
}
709
var res = [],
711
items.forEach(function(item){
713
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
714
}catch(err){
715
throw err
716
}
718
$B.repr.leave(self)
Mar 7, 2018
719
return "{" + res.join(", ") + "}"
Sep 5, 2014
720
}
721
722
dict.__ror__ = function(self, other){
723
// PEP 584
724
if(! _b_.isinstance(other, dict)){
725
return _b_.NotImplemented
726
}
727
var res = dict.copy(other)
728
dict.update(res, self)
729
return res
730
}
731
732
dict.__setitem__ = function(self, key, value){
Mar 7, 2018
733
var $ = $B.args("__setitem__", 3, {self: null, key: null, value: null},
734
["self", "key", "value"], arguments, {}, null, null)
735
return dict.$setitem($.self, $.key, $.value)
736
}
Nov 21, 2015
737
738
dict.$setitem = function(self, key, value, $hash){
739
// Set a dictionary item mapping key and value.
740
//
741
// If key is a string, set:
742
// - $string_dict[key] = [value, order] where "order" is an auto-increment
743
// unique id to keep track of insertion order
744
// - $str_hash[hash(key)] to key
745
//
746
// If key is a number, set $numeric_dict[key] = value
747
//
748
// If key is another object, compute its hash value:
749
// - if the hash is a key of $str_hash, and key == $str_hash[hash],
750
// replace $string_dict[$str_hash[hash]] by value
751
// - if the hash is a key of $numeric_dict, and hash == key, replace
752
// $numeric_dict[hash] by value
753
// - if the hash is a key of $object_dict: $object_dict[hash] is a list
754
// of [k, v] pairs. If key is equal to one of the "k", replace the
755
// matching v by value. Otherwise, add [key, value] to the list
756
// - else set $object_dict[hash] = [[key, value]]
757
//
758
// In all cases, increment attribute $version, used to detect dictionary
759
// changes during an iteration.
761
// Parameter $hash is only set if this method is called by setdefault.
762
// In this case the hash of key has already been computed and we
763
// know that the key is not present in the dictionary, so it's no
764
// use computing hash(key) again, nor testing equality of keys
766
if(self.$from_js){
767
// dictionary created by method to_dict of JSObj instances
768
value = $B.pyobj2jsobj(value)
769
}
770
if(self.$jsobj.__class__ === _b_.type){
771
self.$jsobj[key] = value
772
if(key == "__init__" || key == "__new__"){
773
// If class attribute __init__ or __new__ are reset,
774
// the factory function has to change
775
self.$jsobj.$factory = $B.$instance_creator(self.$jsobj)
776
}
777
}else{
778
self.$jsobj[key] = value
782
if(key instanceof String){
783
key = key.valueOf()
784
}
786
switch(typeof key){
787
case "string":
788
if(self.$string_dict === undefined){
789
console.log("pas de string dict", self, key, value)
790
}
791
if(self.$string_dict[key] !== undefined){
792
self.$string_dict[key][0] = value
793
}else{
794
self.$string_dict[key] = [value, self.$order++]
795
self.$str_hash[str_hash(key)] = key
796
self.$version++
797
}
798
return $N
799
case "number":
800
if(self.$numeric_dict[key] !== undefined){
801
// existing key: preserve order
802
self.$numeric_dict[key][0] = value
803
}else{
804
// special case for 0 and 1 if True or False are keys
805
var done = false
806
if((key == 0 || key == 1) &&
807
self.$object_dict[key] !== undefined){
808
for(const item of self.$object_dict[key]){
809
if((key == 0 && item[0] === false) ||
810
(key == 1 && item[0] === true)){
811
// replace value
812
item[1][0] = value
813
done = true
814
}
815
}
816
}
817
if(! done){
818
// new key
819
self.$numeric_dict[key] = [value, self.$order++]
820
}
823
return $N
824
case "boolean":
825
// true replaces 1 and false replaces 0
826
var num = key ? 1 : 0
827
if(self.$numeric_dict[num] !== undefined){
828
var order = self.$numeric_dict[num][1] // preserve order
829
self.$numeric_dict[num] = [value, order]
830
return
831
}
832
if(self.$object_dict[num] !== undefined){
833
self.$object_dict[num].push([key, [value, self.$order++]])
834
}else{
835
self.$object_dict[num] = [[key, [value, self.$order++]]]
836
}
839
// if we got here the key is more complex, use default method
840
841
var hash = $hash === undefined ? _b_.hash(key) : $hash,
842
_eq = function(other){return $B.rich_comp("__eq__", key, other)}
843
844
if(self.$numeric_dict[hash] !== undefined && _eq(hash)){
845
self.$numeric_dict[hash] = [value, self.$numeric_dict[hash][1]]
849
var sk = self.$str_hash[hash]
850
if(sk !== undefined && _eq(sk)){
851
self.$string_dict[sk] = [value, self.$string_dict[sk][1]]
856
// If $setitem is called from setdefault, don't test equality of key
857
// with any object
858
if($hash){
859
if(self.$object_dict[$hash] !== undefined){
860
self.$object_dict[$hash].push([key, [value, self.$order++]])
862
self.$object_dict[$hash] = [[key, [value, self.$order++]]]
863
}
864
self.$version++
865
return $N
866
}
867
var ix = rank(self, hash, key)
868
if(ix > -1){
869
// reset value
870
self.$object_dict[hash][ix][1] = [value,
871
self.$object_dict[hash][ix][1][1]]
872
return $N
873
}else if(self.$object_dict.hasOwnProperty(hash)){
874
self.$object_dict[hash].push([key, [value, self.$order++]])
876
self.$object_dict[hash] = [[key, [value, self.$order++]]]
Sep 5, 2014
880
}
881
882
// add "reflected" methods
Feb 11, 2018
883
$B.make_rmethods(dict)
Sep 5, 2014
884
Feb 11, 2018
885
dict.clear = function(){
Sep 5, 2014
886
// Remove all items from the dictionary.
Mar 7, 2018
887
var $ = $B.args("clear", 1, {self: null}, ["self"], arguments, {},
888
null, null),
889
self = $.self
891
self.$numeric_dict = {}
892
self.$string_dict = {}
893
self.$str_hash = {}
894
self.$object_dict = {}
896
if(self.$jsobj){
897
for(var attr in self.$jsobj){
Mar 7, 2018
898
if(attr.charAt(0) !== "$" && attr !== "__class__"){
899
delete self.$jsobj[attr]
900
}
901
}
902
}
Sep 5, 2014
906
}
907
Feb 11, 2018
908
dict.copy = function(self){
Sep 5, 2014
909
// Return a shallow copy of the dictionary
Mar 7, 2018
910
var $ = $B.args("copy", 1, {self: null},["self"], arguments,{},
911
null, null),
912
self = $.self,
Sep 5, 2014
915
return res
916
}
917
Feb 11, 2018
918
dict.fromkeys = function(){
Nov 21, 2015
919
Mar 7, 2018
920
var $ = $B.args("fromkeys", 3, {cls: null, keys: null, value: null},
921
["cls", "keys", "value"], arguments, {value: _b_.None}, null, null),
922
keys = $.keys,
923
value = $.value
Sep 5, 2014
925
// class method
926
var klass = $.cls,
Sep 5, 2014
930
while(1){
931
try{
932
var key = _b_.next(keys_iter)
933
if(klass === dict){dict.$setitem(res, key, value)}
934
else{$B.$getattr(res, "__setitem__")(key, value)}
Sep 5, 2014
935
}catch(err){
936
if($B.is_exc(err, [_b_.StopIteration])){
Sep 5, 2014
937
return res
938
}
939
throw err
940
}
941
}
942
}
943
Feb 11, 2018
944
dict.get = function(){
Mar 7, 2018
945
var $ = $B.args("get", 3, {self: null, key: null, _default: null},
946
["self", "key", "_default"], arguments, {_default: $N}, null, null)
948
try{
949
// call $getitem with ignore_missign set to true
950
return dict.$getitem($.self, $.key, true)
951
}catch(err){
952
if(_b_.isinstance(err, _b_.KeyError)){return $._default}
953
else{throw err}
954
}
955
}
956
957
var dict_items = $B.make_view("dict_items", true)
958
dict_items.$iterator = $B.make_iterator_class("dict_itemiterator")
959
Feb 11, 2018
960
dict.items = function(self){
Mar 23, 2018
961
if(arguments.length > 1){
962
var _len = arguments.length - 1,
963
_msg = "items() takes no arguments (" + _len + " given)"
964
throw _b_.TypeError.$factory(_msg)
965
}
966
var items = to_list(self),
967
set_like = true
968
// Check if all values are hashable
969
for(var i = 0, len = items.length; i < len; i++){
970
try{
971
_b_.hash(items[i][1])
972
}catch(err){
973
set_like = false
974
break
975
}
976
}
977
var values = to_list(self)
978
var it = dict_items.$factory(self, values, set_like)
979
it.dict_version = self.$version
981
}
982
984
var dict_keys = $B.make_view("dict_keys")
985
dict_keys.$iterator = $B.make_iterator_class("dict_keyiterator")
Nov 21, 2015
986
987
dict.keys = function(self){
Mar 23, 2018
988
if(arguments.length > 1){
989
var _len = arguments.length - 1,
990
_msg = "keys() takes no arguments (" + _len + " given)"
991
throw _b_.TypeError.$factory(_msg)
Nov 21, 2015
992
}
993
var it = dict_keys.$factory(self, to_list(self, 0), true)
994
it.dict_version = self.$version
Nov 21, 2015
996
}
997
Feb 11, 2018
998
dict.pop = function(){
Nov 21, 2015
999
1000
var missing = {},
1001
$ = $B.args("pop", 3, {self: null, key: null, _default: null},
1002
["self", "key", "_default"], arguments, {_default: missing}, null, null),
1003
self = $.self,
1004
key = $.key,
1005
_default = $._default
Nov 21, 2015
1006
Sep 5, 2014
1007
try{
1008
var res = dict.__getitem__(self, key)
1009
dict.__delitem__(self, key)
Sep 5, 2014
1010
return res
1011
}catch(err){
1012
if(err.__class__ === _b_.KeyError){
1013
if(_default !== missing){return _default}
Sep 5, 2014
1014
throw err
1015
}
1016
throw err
1017
}
1018
}
1019
Feb 11, 2018
1020
dict.popitem = function(self){
1022
var itm = _b_.next(_b_.iter(dict.items(self)))
1023
dict.__delitem__(self, itm[0])
Feb 11, 2018
1024
return _b_.tuple.$factory(itm)
1026
if (err.__class__ == _b_.StopIteration) {
1027
throw _b_.KeyError.$factory("'popitem(): dictionary is empty'")
Sep 5, 2014
1030
}
1031
Feb 11, 2018
1032
dict.setdefault = function(){
Nov 21, 2015
1033
Mar 7, 2018
1034
var $ = $B.args("setdefault", 3, {self: null, key: null, _default: null},
1035
["self", "key", "_default"], arguments, {_default: $N}, null, null),
1036
self = $.self,
1037
key = $.key,
1038
_default = $._default
1039
try{
1040
// Pass 3rd argument to dict.$getitem to avoid using __missing__
1041
// Cf. issue #1598
1042
return dict.$getitem(self, key, true)
1043
}catch(err){
1044
if(err.__class__ !== _b_.KeyError){
1045
throw err
1046
}
1047
if(_default === undefined){_default = $N}
1048
var hash = key.$hash
1049
key.$hash = undefined
1050
dict.$setitem(self, key, _default, hash)
Sep 5, 2014
1051
return _default
1052
}
1053
}
1054
Feb 11, 2018
1055
dict.update = function(self){
Nov 21, 2015
1056
Mar 7, 2018
1057
var $ = $B.args("update", 1, {"self": null}, ["self"], arguments,
1058
{}, "args", "kw"),
1059
self = $.self,
1060
args = $.args,
1061
kw = $.kw
1062
if(args.length > 0){
1063
var o = args[0]
1065
if(o.$jsobj){
1066
o = jsobj2dict(o.$jsobj)
1067
}
1069
}else if(_b_.hasattr(o, "keys")){
1070
var _keys = _b_.list.$factory($B.$call($B.$getattr(o, "keys"))())
1071
for(var i = 0, len = _keys.length; i < len; i++){
1072
var _value = $B.$getattr(o, "__getitem__")(_keys[i])
1073
dict.$setitem(self, _keys[i], _value)
1074
}
1075
}else{
1076
var it = _b_.iter(o),
1077
i = 0
1078
while(true){
1079
try{
1080
var item = _b_.next(it)
1081
}catch(err){
1082
if(err.__class__ === _b_.StopIteration){break}
1083
throw err
1084
}
1085
try{
1086
key_value = _b_.list.$factory(item)
1087
}catch(err){
1088
throw _b_.TypeError.$factory("cannot convert dictionary" +
1089
" update sequence element #" + i + " to a sequence")
1090
}
1091
if(key_value.length !== 2){
1092
throw _b_.ValueError.$factory("dictionary update " +
1093
"sequence element #" + i + " has length " +
1094
key_value.length + "; 2 is required")
1095
}
1096
dict.$setitem(self, key_value[0], key_value[1])
1097
i++
Sep 5, 2014
1100
}
Sep 5, 2014
1104
}
1105
1106
var dict_values = $B.make_view("dict_values")
1107
dict_values.$iterator = $B.make_iterator_class("dict_valueiterator")
Nov 21, 2015
1108
Feb 11, 2018
1109
dict.values = function(self){
Mar 23, 2018
1110
if(arguments.length > 1){
1111
var _len = arguments.length - 1,
1112
_msg = "values() takes no arguments (" + _len + " given)"
1113
throw _b_.TypeError.$factory(_msg)
Nov 21, 2015
1114
}
1115
var values = to_list(self, 1)
1116
var it = dict_values.$factory(self, values, false)
1117
it.dict_version = self.$version
Nov 21, 2015
1119
}
1120
1121
dict.$factory = function(){
1122
var res = dict.__new__(dict)
1123
var args = [res]
1124
for(var i = 0, len = arguments.length; i < len ; i++){
1125
args.push(arguments[i])
1126
}
1127
dict.__init__.apply(null, args)
Sep 5, 2014
1128
return res
1129
}
Sep 5, 2014
1131
_b_.dict = dict
Feb 11, 2018
1133
$B.set_func_names(dict, "builtins")
1134
1135
dict.__class_getitem__ = _b_.classmethod.$factory(dict.__class_getitem__)
1136
1137
$B.empty_dict = function(){
1138
return {
1139
__class__: dict,
1140
$numeric_dict : {},
1141
$object_dict : {},
1142
$string_dict : {},
1143
$str_hash: {},
1144
$version: 0,
1145
$order: 0
1149
// This must be done after set_func_names, otherwise dict.fromkeys doesn't
1150
// have the attribute $infos
1151
dict.fromkeys = _b_.classmethod.$factory(dict.fromkeys)
1152
1153
$B.getset_descriptor = $B.make_class("getset_descriptor",
1154
function(klass, attr){
1155
return {
1156
__class__: $B.getset_descriptor,
1157
__doc__: _b_.None,
1158
cls: klass,
1159
attr: attr
1160
}
1161
}
1162
)
1163
1164
$B.getset_descriptor.__repr__ = $B.getset_descriptor.__str__ = function(self){
1165
return `<attribute '${self.attr}' of '${self.cls.$infos.__name__}' objects>`
1166
}
1167
1168
$B.set_func_names($B.getset_descriptor, "builtins")
1169
1170
// Class for attribute __dict__ of classes
1171
var mappingproxy = $B.mappingproxy = $B.make_class("mappingproxy",
Feb 12, 2018
1172
function(obj){
1173
if(_b_.isinstance(obj, dict)){
1174
// obj is a dictionary, with $string_dict table such that
1175
// obj.$string_dict[key] = [value, rank]
1176
// Transform it into an object with attribute $jsobj such that
1177
// res.$jsobj[key] = value
1178
var res = $B.obj_dict(dict.$to_obj(obj))
1179
}else{
1180
var res = $B.obj_dict(obj)
1181
}
Feb 12, 2018
1182
res.__class__ = mappingproxy
1183
return res
1184
}
1185
)
1187
mappingproxy.$match_mapping_pattern = true // for pattern matching (PEP 634)
1188
Feb 12, 2018
1189
mappingproxy.__setitem__ = function(){
Mar 7, 2018
1190
throw _b_.TypeError.$factory("'mappingproxy' object does not support " +
1191
"item assignment")
1194
for(var attr in dict){
1195
if(mappingproxy[attr] !== undefined ||
1196
["__class__", "__mro__", "__new__", "__init__", "__delitem__",
1197
"clear", "fromkeys", "pop", "popitem", "setdefault",
1198
"update"].indexOf(attr) > -1){
1199
continue
1200
}
1201
if(typeof dict[attr] == "function"){
1202
mappingproxy[attr] = (function(key){
1203
return function(){
1204
return dict[key].apply(null, arguments)
1205
}
1206
})(attr)
1207
}else{
1208
mappingproxy[attr] = dict[attr]
1209
}
1210
}
1211
Feb 12, 2018
1212
$B.set_func_names(mappingproxy, "builtins")
Mar 7, 2018
1217
if(attr.charAt(0) != "$" && attr !== "__class__"){
1218
if(x[attr] === null){
1219
d.$string_dict[attr] = [_b_.None, d.$order++]
1220
}else if(x[attr] === undefined){
1221
continue
1222
}else if(x[attr].$jsobj === x){
1223
d.$string_dict[attr] = [d, d.$order++]
1225
d.$string_dict[attr] = [$B.$JS2Py(x[attr]), d.$order++]
1227
}
1228
}
1229
return d
1230
}
1232
$B.obj_dict = function(obj, from_js){
1233
var klass = obj.__class__ || $B.get_class(obj)
1234
if(klass !== undefined && klass.$native){
1235
throw $B.attr_error("__dict__", obj)
1236
}
1238
res.$jsobj = obj
1239
res.$from_js = from_js // set to true if
1240
return res
1241
}
1242
Sep 5, 2014
1243
})(__BRYTHON__)