Skip to content
Permalink
Newer
Older
100644 1406 lines (1268 sloc) 40.7 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){
195
if((! attr.startsWith("$")) &&
196
((! d.$exclude) || ! d.$exclude(attr))){
197
var val = d.$jsobj[attr]
198
if(val === undefined){val = _b_.NotImplemented}
199
else if(val === null){val = $N}
203
}else if(_b_.isinstance(d, _b_.dict)){
204
for(var k in d.$numeric_dict){
205
items.push([parseFloat(k), d.$numeric_dict[k]])
206
}
208
for(var k in d.$string_dict){
209
items.push([k, d.$string_dict[k]])
210
}
212
for(var k in d.$object_dict){
213
d.$object_dict[k].forEach(function(item){
214
items.push(item)
215
})
216
}
218
// sort by insertion order
219
items.sort(function(a, b){
220
return a[1][1] - b[1][1]
221
})
222
items = items.map(function(item){return [item[0], item[1][0]]})
225
res = items.map(function(item){return item[ix]})
226
return res
227
}else{
228
items.__class__ = _b_.tuple
229
return items.map(function(item){
230
item.__class__ = _b_.tuple; return item}
231
)
232
}
Feb 9, 2015
234
235
$B.dict_to_list = to_list // used in py_types.js
236
237
var $copy_dict = function(left, right){
239
si = dict.$setitem
240
right.$version = right.$version || 0
241
var right_version = right.$version || 0
242
for(var i = 0, len = _l.length; i < len; i++){
243
si(left, _l[i][0], _l[i][1])
244
if(right.$version != right_version){
245
throw _b_.RuntimeError.$factory("dict mutated during update")
246
}
247
}
250
function rank(self, hash, key){
251
// Search if object key, with hash = hash(key), is in
252
// self.$object_dict
253
var pairs = self.$object_dict[hash]
254
if(pairs !== undefined){
255
for(var i = 0, len = pairs.length; i < len; i++){
256
if($B.rich_comp("__eq__", key, pairs[i][0])){
257
return i
258
}
259
}
260
}
261
return -1
262
}
263
Feb 11, 2018
264
dict.__bool__ = function () {
Mar 7, 2018
265
var $ = $B.args("__bool__", 1, {self: null}, ["self"],
266
arguments, {}, null, null)
Feb 11, 2018
267
return dict.__len__($.self) > 0
270
dict.__class_getitem__ = function(cls, item){
271
// PEP 585
272
// Set as a classmethod at the end of this script, after $B.set_func_names()
273
if(! Array.isArray(item)){
274
item = [item]
275
}
276
return $B.GenericAlias.$factory(cls, item)
277
}
278
Feb 11, 2018
279
dict.__contains__ = function(){
280
var $ = $B.args("__contains__", 2, {self: null, key: null},
281
["self", "key"], arguments, {}, null, null),
282
self = $.self,
285
if(self.$jsobj){
286
return self.$jsobj[key] !== undefined
287
}
289
switch(typeof key) {
291
return self.$string_dict[key] !== undefined
293
return self.$numeric_dict[key] !== undefined
294
}
295
296
var hash = _b_.hash(key)
297
if(self.$str_hash[hash] !== undefined &&
298
$B.rich_comp("__eq__", key, self.$str_hash[hash])){
299
return true
300
}
301
if(self.$numeric_dict[hash] !== undefined &&
302
$B.rich_comp("__eq__", key, hash)){
303
return true
304
}
305
return rank(self, hash, key) > -1
Sep 5, 2014
306
}
307
Feb 11, 2018
308
dict.__delitem__ = function(){
Nov 21, 2015
309
310
var $ = $B.args("__eq__", 2, {self: null, arg: null},
311
["self", "arg"], arguments, {}, null, null),
312
self = $.self,
Nov 21, 2015
314
315
if(self.$jsobj){
316
if(self.$jsobj[arg] === undefined){throw _b_.KeyError.$factory(arg)}
317
delete self.$jsobj[arg]
320
switch(typeof arg){
321
case "string":
322
if(self.$string_dict[arg] === undefined){
323
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
324
}
325
delete self.$string_dict[arg]
326
delete self.$str_hash[str_hash(arg)]
328
return $N
329
case "number":
330
if(self.$numeric_dict[arg] === undefined){
331
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
333
delete self.$numeric_dict[arg]
337
// go with defaults
338
339
var hash = _b_.hash(arg),
340
ix
342
if((ix = rank(self, hash, arg)) > -1){
343
self.$object_dict[hash].splice(ix, 1)
344
}else{
345
throw _b_.KeyError.$factory(_b_.str.$factory(arg))
Sep 5, 2014
350
}
351
Feb 11, 2018
352
dict.__eq__ = function(){
Mar 7, 2018
353
var $ = $B.args("__eq__", 2, {self: null, other: null},
354
["self", "other"], arguments, {}, null, null),
355
self = $.self,
356
other = $.other
358
if(! _b_.isinstance(other, dict)){return false}
360
if(self.$jsobj){self = jsobj2dict(self.$jsobj)}
361
if(other.$jsobj){other = jsobj2dict(other.$jsobj)}
362
if(dict.__len__(self) != dict.__len__(other)){
363
return false
364
}
366
if(self.$string_dict.length != other.$string_dict.length){
370
for(var k in self.$numeric_dict){
371
if(other.$numeric_dict.hasOwnProperty(k)){
372
if(!$B.rich_comp("__eq__", other.$numeric_dict[k][0],
373
self.$numeric_dict[k][0])){
374
return false
375
}
376
}else if(other.$object_dict.hasOwnProperty(k)){
377
var pairs = other.$object_dict[k],
378
flag = false
379
for(var i = 0, len = pairs.length; i < len; i++){
380
if($B.rich_comp("__eq__", k, pairs[i][0]) &&
381
$B.rich_comp("__eq__", self.$numeric_dict[k],
382
pairs[i][1])){
383
flag = true
384
break
385
}
387
if(! flag){return false}
Nov 21, 2015
390
}
391
}
392
for(var k in self.$string_dict){
393
if(!other.$string_dict.hasOwnProperty(k) ||
394
!$B.rich_comp("__eq__", other.$string_dict[k][0],
395
self.$string_dict[k][0])){
Nov 21, 2015
397
}
398
}
399
for(var hash in self.$object_dict){
400
var pairs = self.$object_dict[hash]
401
// Get all (key, value) pairs in other that have the same hash
402
var other_pairs = []
403
if(other.$numeric_dict[hash] !== undefined){
404
other_pairs.push([hash, other.$numeric_dict[hash]])
405
}
406
if(other.$object_dict[hash] !== undefined){
407
other_pairs = other_pairs.concat(other.$object_dict[hash])
408
}
409
if(other_pairs.length == 0){
410
return false
411
}
412
for(var i = 0, len_i = pairs.length; i < len_i; i++){
413
var flag = false
414
var key = pairs[i][0],
415
value = pairs[i][1][0]
416
for(var j = 0, len_j = other_pairs.length; j < len_j; j++){
417
if($B.rich_comp("__eq__", key, other_pairs[j][0]) &&
418
$B.rich_comp("__eq__", value, other_pairs[j][1][0])){
419
flag = true
420
break
426
}
427
}
428
return true
Sep 5, 2014
429
}
430
Feb 11, 2018
431
dict.__getitem__ = function(){
432
var $ = $B.args("__getitem__", 2, {self: null, arg: null},
433
["self", "arg"], arguments, {}, null, null),
434
self = $.self,
436
return dict.$getitem(self, arg)
437
}
438
439
dict.$getitem = function(self, arg, ignore_missing){
440
// ignore_missing is set in dict.get and dict.setdefault
441
if(self.$jsobj){
442
if(self.$exclude && self.$exclude(arg)){
443
throw _b_.KeyError.$factory(arg)
444
}
445
if(self.$jsobj[arg] === undefined){
446
if(self.$jsobj.hasOwnProperty &&
447
self.$jsobj.hasOwnProperty(arg)){
449
}
450
throw _b_.KeyError.$factory(arg)
451
}
452
return self.$jsobj[arg]
454
455
switch(typeof arg){
456
case "string":
457
var x = self.$string_dict[arg]
458
if(x !== undefined){
459
return x[0]
461
break
462
case "number":
463
if(self.$numeric_dict[arg] !== undefined){
464
return self.$numeric_dict[arg][0]
466
break
467
}
468
469
// since the key is more complex use 'default' method of getting item
470
471
var hash = _b_.hash(arg),
472
_eq = function(other){return $B.rich_comp("__eq__", arg, other)}
473
474
if(typeof arg == "object"){
475
arg.$hash = hash // cache for setdefault
476
}
477
var sk = self.$str_hash[hash]
478
if(sk !== undefined && _eq(sk)){
479
return self.$string_dict[sk][0]
481
if(self.$numeric_dict[hash] !== undefined && _eq(hash)){
482
return self.$numeric_dict[hash][0]
484
if(_b_.isinstance(arg, _b_.str)){
485
// string subclass
486
var res = self.$string_dict[arg.valueOf()]
487
if(res !== undefined){return res[0]}
490
var ix = rank(self, hash, arg)
491
if(ix > -1){
492
return self.$object_dict[hash][ix][1][0]
495
if(! ignore_missing){
496
if(self.__class__ !== dict && ! ignore_missing){
497
try{
498
var missing_method = $B.$getattr(self.__class__,
499
"__missing__", _b_.None)
500
}catch(err){
501
console.log(err)
503
}
504
if(missing_method !== _b_.None){
505
return missing_method(self, arg)
506
}
509
throw _b_.KeyError.$factory(arg)
Sep 5, 2014
510
}
511
512
dict.__hash__ = _b_.None
Sep 5, 2014
513
514
function init_from_list(self, args){
515
var i = -1,
516
stop = args.length - 1,
517
si = dict.__setitem__
518
while(i++ < stop){
519
var item = args[i]
520
if(item.length != 2){
521
throw _b_.ValueError.$factory("dictionary " +
522
`update sequence element #${i} has length 1; 2 is required`)
523
}
524
switch(typeof item[0]) {
525
case 'string':
526
self.$string_dict[item[0]] = [item[1], self.$order++]
527
self.$str_hash[str_hash(item[0])] = item[0]
528
self.$version++
529
break
530
case 'number':
531
if(item[0] != 0 && item[0] != 1){
532
self.$numeric_dict[item[0]] = [item[1], self.$order++]
533
self.$version++
534
break
535
}
536
default:
537
si(self, item[0], item[1])
538
break
539
}
540
}
541
}
542
543
dict.__init__ = function(self, first, second){
544
if(first === undefined){
545
return $N
546
}
548
if(first.$nat != 'kw' && $B.get_class(first) === $B.JSObj){
549
for(var key in first){
550
self.$string_dict[key] = [first[key], self.$order++]
551
}
552
return _b_.None
553
}else if(first.$jsobj){
554
self.$jsobj = {}
555
for(var attr in first.$jsobj){
556
self.$jsobj[attr] = first.$jsobj[attr]
559
}else if(Array.isArray(first)){
560
init_from_list(self, first)
561
return $N
Sep 5, 2014
562
}
565
var $ = $B.args("dict", 1, {self:null}, ["self"],
566
arguments, {}, "first", "second")
567
var args = $.first
568
if(args.length > 1){
569
throw _b_.TypeError.$factory("dict expected at most 1 argument" +
570
", got 2")
571
}else if(args.length == 1){
572
args = args[0]
573
if(args.__class__ === dict){
574
['$string_dict', '$str_hash', '$numeric_dict', '$object_dict'].
575
forEach(function(d){
576
for(key in args[d]){self[d][key] = args[d][key]}
577
})
578
}else if(_b_.isinstance(args, dict)){
581
var keys = $B.$getattr(args, "keys", null)
582
if(keys !== null){
583
var gi = $B.$getattr(args, "__getitem__", null)
584
if(gi !== null){
585
// has keys and __getitem__ : it's a mapping, iterate on
586
// keys and values
587
gi = $B.$call(gi)
588
var kiter = _b_.iter($B.$call(keys)())
589
while(true){
590
try{
591
var key = _b_.next(kiter),
592
value = gi(key)
593
dict.__setitem__(self, key, value)
594
}catch(err){
595
if(err.__class__ === _b_.StopIteration){
596
break
597
}
598
throw err
599
}
600
}
601
return $N
602
}
603
}
604
if(! Array.isArray(args)){
605
args = _b_.list.$factory(args)
606
}
607
// Form "dict([[key1, value1], [key2,value2], ...])"
608
init_from_list(self, args)
Sep 5, 2014
609
}
611
var kw = $.second.$string_dict
612
for(var attr in kw){
613
switch(typeof attr){
614
case "string":
615
self.$string_dict[attr] = [kw[attr][0], self.$order++]
616
self.$str_hash[str_hash(attr)] = attr
617
break
618
case "number":
619
self.$numeric_dict[attr] = [kw[attr][0], self.$order++]
622
si(self, attr, kw[attr][0])
Sep 5, 2014
627
}
628
629
dict.__iter__ = function(self){
630
return _b_.iter(dict.keys(self))
Sep 5, 2014
631
}
632
633
dict.__ior__ = function(self, other){
634
// PEP 584
635
dict.update(self, other)
636
return self
637
}
638
Feb 11, 2018
639
dict.__len__ = function(self) {
642
if(self.$jsobj){
643
for(var attr in self.$jsobj){
644
if(attr.charAt(0) != "$" &&
645
((! self.$exclude) || ! self.$exclude(attr))){
646
_count++
647
}
648
}
649
return _count
650
}
652
for(var k in self.$numeric_dict){_count++}
653
for(var k in self.$string_dict){_count++}
654
for(var hash in self.$object_dict){
655
_count += self.$object_dict[hash].length
656
}
Sep 5, 2014
660
661
dict.__ne__ = function(self, other){
662
return ! dict.__eq__(self, other)
663
}
Sep 5, 2014
664
Feb 11, 2018
665
dict.__new__ = function(cls){
666
if(cls === undefined){
Mar 7, 2018
667
throw _b_.TypeError.$factory("int.__new__(): not enough arguments")
669
var instance = {
671
$numeric_dict : {},
672
$object_dict : {},
675
$version: 0,
676
$order: 0
678
if(cls !== dict){
679
instance.__dict__ = $B.empty_dict()
680
}
681
return instance
684
dict.__or__ = function(self, other){
685
// PEP 584
686
if(! _b_.isinstance(other, dict)){
687
return _b_.NotImplemented
688
}
689
var res = dict.copy(self)
690
dict.update(res, other)
691
return res
692
}
693
694
function __newobj__(){
695
// __newobj__ is called with a generator as only argument
696
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
697
args = $.args
698
var res = $B.empty_dict()
699
res.__class__ = args[0]
700
return res
701
}
702
703
dict.__reduce_ex__ = function(self, protocol){
704
return $B.fast_tuple([
705
__newobj__,
706
$B.fast_tuple([self.__class__]),
707
_b_.None,
708
_b_.None,
709
dict.items(self)])
710
}
711
Feb 11, 2018
712
dict.__repr__ = function(self){
713
$B.builtins_repr_check(dict, arguments) // in brython_builtins.js
714
if(self.$jsobj){ // wrapper around Javascript object
715
return dict.__repr__(jsobj2dict(self.$jsobj, self.$exclude))
717
if($B.repr.enter(self)){
718
return "{...}"
719
}
720
var res = [],
722
items.forEach(function(item){
724
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
725
}catch(err){
726
throw err
727
}
729
$B.repr.leave(self)
Mar 7, 2018
730
return "{" + res.join(", ") + "}"
Sep 5, 2014
731
}
732
733
dict.__ror__ = function(self, other){
734
// PEP 584
735
if(! _b_.isinstance(other, dict)){
736
return _b_.NotImplemented
737
}
738
var res = dict.copy(other)
739
dict.update(res, self)
740
return res
741
}
742
743
dict.__setitem__ = function(self, key, value){
Mar 7, 2018
744
var $ = $B.args("__setitem__", 3, {self: null, key: null, value: null},
745
["self", "key", "value"], arguments, {}, null, null)
746
return dict.$setitem($.self, $.key, $.value)
747
}
Nov 21, 2015
748
749
dict.$setitem = function(self, key, value, $hash){
750
// Set a dictionary item mapping key and value.
751
//
752
// If key is a string, set:
753
// - $string_dict[key] = [value, order] where "order" is an auto-increment
754
// unique id to keep track of insertion order
755
// - $str_hash[hash(key)] to key
756
//
757
// If key is a number, set $numeric_dict[key] = value
758
//
759
// If key is another object, compute its hash value:
760
// - if the hash is a key of $str_hash, and key == $str_hash[hash],
761
// replace $string_dict[$str_hash[hash]] by value
762
// - if the hash is a key of $numeric_dict, and hash == key, replace
763
// $numeric_dict[hash] by value
764
// - if the hash is a key of $object_dict: $object_dict[hash] is a list
765
// of [k, v] pairs. If key is equal to one of the "k", replace the
766
// matching v by value. Otherwise, add [key, value] to the list
767
// - else set $object_dict[hash] = [[key, value]]
768
//
769
// In all cases, increment attribute $version, used to detect dictionary
770
// changes during an iteration.
772
// Parameter $hash is only set if this method is called by setdefault.
773
// In this case the hash of key has already been computed and we
774
// know that the key is not present in the dictionary, so it's no
775
// use computing hash(key) again, nor testing equality of keys
777
if(self.$from_js){
778
// dictionary created by method to_dict of JSObj instances
779
value = $B.pyobj2jsobj(value)
780
}
781
if(self.$jsobj.__class__ === _b_.type){
782
self.$jsobj[key] = value
783
if(key == "__init__" || key == "__new__"){
784
// If class attribute __init__ or __new__ are reset,
785
// the factory function has to change
786
self.$jsobj.$factory = $B.$instance_creator(self.$jsobj)
787
}
788
}else{
789
self.$jsobj[key] = value
793
if(key instanceof String){
794
key = key.valueOf()
795
}
797
switch(typeof key){
798
case "string":
799
if(self.$string_dict === undefined){
800
console.log("pas de string dict", self, key, value)
801
}
802
if(self.$string_dict[key] !== undefined){
803
self.$string_dict[key][0] = value
804
}else{
805
self.$string_dict[key] = [value, self.$order++]
806
self.$str_hash[str_hash(key)] = key
807
self.$version++
808
}
809
return $N
810
case "number":
811
if(self.$numeric_dict[key] !== undefined){
812
// existing key: preserve order
813
self.$numeric_dict[key][0] = value
814
}else{
815
// special case for 0 and 1 if True or False are keys
816
var done = false
817
if((key == 0 || key == 1) &&
818
self.$object_dict[key] !== undefined){
819
for(const item of self.$object_dict[key]){
820
if((key == 0 && item[0] === false) ||
821
(key == 1 && item[0] === true)){
822
// replace value
823
item[1][0] = value
824
done = true
825
}
826
}
827
}
828
if(! done){
829
// new key
830
self.$numeric_dict[key] = [value, self.$order++]
831
}
834
return $N
835
case "boolean":
836
// true replaces 1 and false replaces 0
837
var num = key ? 1 : 0
838
if(self.$numeric_dict[num] !== undefined){
839
var order = self.$numeric_dict[num][1] // preserve order
840
self.$numeric_dict[num] = [value, order]
841
return
842
}
843
if(self.$object_dict[num] !== undefined){
844
self.$object_dict[num].push([key, [value, self.$order++]])
845
}else{
846
self.$object_dict[num] = [[key, [value, self.$order++]]]
847
}
850
// if we got here the key is more complex, use default method
851
852
var hash = $hash === undefined ? _b_.hash(key) : $hash,
853
_eq = function(other){return $B.rich_comp("__eq__", key, other)}
854
855
if(self.$numeric_dict[hash] !== undefined && _eq(hash)){
856
self.$numeric_dict[hash] = [value, self.$numeric_dict[hash][1]]
860
var sk = self.$str_hash[hash]
861
if(sk !== undefined && _eq(sk)){
862
self.$string_dict[sk] = [value, self.$string_dict[sk][1]]
867
// If $setitem is called from setdefault, don't test equality of key
868
// with any object
869
if($hash){
870
if(self.$object_dict[$hash] !== undefined){
871
self.$object_dict[$hash].push([key, [value, self.$order++]])
873
self.$object_dict[$hash] = [[key, [value, self.$order++]]]
874
}
875
self.$version++
876
return $N
877
}
878
var ix = rank(self, hash, key)
879
if(ix > -1){
880
// reset value
881
self.$object_dict[hash][ix][1] = [value,
882
self.$object_dict[hash][ix][1][1]]
883
return $N
884
}else if(self.$object_dict.hasOwnProperty(hash)){
885
self.$object_dict[hash].push([key, [value, self.$order++]])
887
self.$object_dict[hash] = [[key, [value, self.$order++]]]
Sep 5, 2014
891
}
892
893
// add "reflected" methods
Feb 11, 2018
894
$B.make_rmethods(dict)
Sep 5, 2014
895
Feb 11, 2018
896
dict.clear = function(){
Sep 5, 2014
897
// Remove all items from the dictionary.
Mar 7, 2018
898
var $ = $B.args("clear", 1, {self: null}, ["self"], arguments, {},
899
null, null),
900
self = $.self
902
self.$numeric_dict = {}
903
self.$string_dict = {}
904
self.$str_hash = {}
905
self.$object_dict = {}
907
if(self.$jsobj){
908
for(var attr in self.$jsobj){
Mar 7, 2018
909
if(attr.charAt(0) !== "$" && attr !== "__class__"){
910
delete self.$jsobj[attr]
911
}
912
}
913
}
Sep 5, 2014
917
}
918
Feb 11, 2018
919
dict.copy = function(self){
Sep 5, 2014
920
// Return a shallow copy of the dictionary
Mar 7, 2018
921
var $ = $B.args("copy", 1, {self: null},["self"], arguments,{},
922
null, null),
923
self = $.self,
Sep 5, 2014
926
return res
927
}
928
Feb 11, 2018
929
dict.fromkeys = function(){
Nov 21, 2015
930
Mar 7, 2018
931
var $ = $B.args("fromkeys", 3, {cls: null, keys: null, value: null},
932
["cls", "keys", "value"], arguments, {value: _b_.None}, null, null),
933
keys = $.keys,
934
value = $.value
Sep 5, 2014
936
// class method
937
var klass = $.cls,
Sep 5, 2014
941
while(1){
942
try{
943
var key = _b_.next(keys_iter)
944
if(klass === dict){dict.$setitem(res, key, value)}
945
else{$B.$getattr(res, "__setitem__")(key, value)}
Sep 5, 2014
946
}catch(err){
947
if($B.is_exc(err, [_b_.StopIteration])){
Sep 5, 2014
948
return res
949
}
950
throw err
951
}
952
}
953
}
954
Feb 11, 2018
955
dict.get = function(){
Mar 7, 2018
956
var $ = $B.args("get", 3, {self: null, key: null, _default: null},
957
["self", "key", "_default"], arguments, {_default: $N}, null, null)
959
try{
960
// call $getitem with ignore_missign set to true
961
return dict.$getitem($.self, $.key, true)
962
}catch(err){
963
if(_b_.isinstance(err, _b_.KeyError)){return $._default}
964
else{throw err}
965
}
966
}
967
968
var dict_items = $B.make_view("dict_items", true)
969
dict_items.$iterator = $B.make_iterator_class("dict_itemiterator")
970
Feb 11, 2018
971
dict.items = function(self){
Mar 23, 2018
972
if(arguments.length > 1){
973
var _len = arguments.length - 1,
974
_msg = "items() takes no arguments (" + _len + " given)"
975
throw _b_.TypeError.$factory(_msg)
976
}
977
var items = to_list(self),
978
set_like = true
979
// Check if all values are hashable
980
for(var i = 0, len = items.length; i < len; i++){
981
try{
982
_b_.hash(items[i][1])
983
}catch(err){
984
set_like = false
985
break
986
}
987
}
988
var values = to_list(self)
989
var it = dict_items.$factory(self, values, set_like)
990
it.dict_version = self.$version
992
}
993
995
var dict_keys = $B.make_view("dict_keys")
996
dict_keys.$iterator = $B.make_iterator_class("dict_keyiterator")
Nov 21, 2015
997
998
dict.keys = function(self){
Mar 23, 2018
999
if(arguments.length > 1){
1000
var _len = arguments.length - 1,
1001
_msg = "keys() takes no arguments (" + _len + " given)"
1002
throw _b_.TypeError.$factory(_msg)
Nov 21, 2015
1003
}
1004
var it = dict_keys.$factory(self, to_list(self, 0), true)
1005
it.dict_version = self.$version
Nov 21, 2015
1007
}
1008
Feb 11, 2018
1009
dict.pop = function(){
Nov 21, 2015
1010
1011
var missing = {},
1012
$ = $B.args("pop", 3, {self: null, key: null, _default: null},
1013
["self", "key", "_default"], arguments, {_default: missing}, null, null),
1014
self = $.self,
1015
key = $.key,
1016
_default = $._default
Nov 21, 2015
1017
Sep 5, 2014
1018
try{
1019
var res = dict.__getitem__(self, key)
1020
dict.__delitem__(self, key)
Sep 5, 2014
1021
return res
1022
}catch(err){
1023
if(err.__class__ === _b_.KeyError){
1024
if(_default !== missing){return _default}
Sep 5, 2014
1025
throw err
1026
}
1027
throw err
1028
}
1029
}
1030
Feb 11, 2018
1031
dict.popitem = function(self){
1033
var itm = _b_.next(_b_.iter(dict.items(self)))
1034
dict.__delitem__(self, itm[0])
Feb 11, 2018
1035
return _b_.tuple.$factory(itm)
1037
if (err.__class__ == _b_.StopIteration) {
1038
throw _b_.KeyError.$factory("'popitem(): dictionary is empty'")
Sep 5, 2014
1041
}
1042
Feb 11, 2018
1043
dict.setdefault = function(){
Nov 21, 2015
1044
Mar 7, 2018
1045
var $ = $B.args("setdefault", 3, {self: null, key: null, _default: null},
1046
["self", "key", "_default"], arguments, {_default: $N}, null, null),
1047
self = $.self,
1048
key = $.key,
1049
_default = $._default
1050
try{
1051
// Pass 3rd argument to dict.$getitem to avoid using __missing__
1052
// Cf. issue #1598
1053
return dict.$getitem(self, key, true)
1054
}catch(err){
1055
if(err.__class__ !== _b_.KeyError){
1056
throw err
1057
}
1058
if(_default === undefined){_default = $N}
1059
var hash = key.$hash
1060
key.$hash = undefined
1061
dict.$setitem(self, key, _default, hash)
Sep 5, 2014
1062
return _default
1063
}
1064
}
1065
Feb 11, 2018
1066
dict.update = function(self){
Nov 21, 2015
1067
Mar 7, 2018
1068
var $ = $B.args("update", 1, {"self": null}, ["self"], arguments,
1069
{}, "args", "kw"),
1070
self = $.self,
1071
args = $.args,
1072
kw = $.kw
1073
if(args.length > 0){
1074
var o = args[0]
1076
if(o.$jsobj){
1077
o = jsobj2dict(o.$jsobj)
1078
}
1080
}else if(_b_.hasattr(o, "keys")){
1081
var _keys = _b_.list.$factory($B.$call($B.$getattr(o, "keys"))())
1082
for(var i = 0, len = _keys.length; i < len; i++){
1083
var _value = $B.$getattr(o, "__getitem__")(_keys[i])
1084
dict.$setitem(self, _keys[i], _value)
1085
}
1086
}else{
1087
var it = _b_.iter(o),
1088
i = 0
1089
while(true){
1090
try{
1091
var item = _b_.next(it)
1092
}catch(err){
1093
if(err.__class__ === _b_.StopIteration){break}
1094
throw err
1095
}
1096
try{
1097
key_value = _b_.list.$factory(item)
1098
}catch(err){
1099
throw _b_.TypeError.$factory("cannot convert dictionary" +
1100
" update sequence element #" + i + " to a sequence")
1101
}
1102
if(key_value.length !== 2){
1103
throw _b_.ValueError.$factory("dictionary update " +
1104
"sequence element #" + i + " has length " +
1105
key_value.length + "; 2 is required")
1106
}
1107
dict.$setitem(self, key_value[0], key_value[1])
1108
i++
Sep 5, 2014
1111
}
Sep 5, 2014
1115
}
1116
1117
var dict_values = $B.make_view("dict_values")
1118
dict_values.$iterator = $B.make_iterator_class("dict_valueiterator")
Nov 21, 2015
1119
Feb 11, 2018
1120
dict.values = function(self){
Mar 23, 2018
1121
if(arguments.length > 1){
1122
var _len = arguments.length - 1,
1123
_msg = "values() takes no arguments (" + _len + " given)"
1124
throw _b_.TypeError.$factory(_msg)
Nov 21, 2015
1125
}
1126
var values = to_list(self, 1)
1127
var it = dict_values.$factory(self, values, false)
1128
it.dict_version = self.$version
Nov 21, 2015
1130
}
1131
1132
dict.$factory = function(){
1133
var res = dict.__new__(dict)
1134
var args = [res]
1135
for(var i = 0, len = arguments.length; i < len ; i++){
1136
args.push(arguments[i])
1137
}
1138
dict.__init__.apply(null, args)
Sep 5, 2014
1139
return res
1140
}
Sep 5, 2014
1142
_b_.dict = dict
Feb 11, 2018
1144
$B.set_func_names(dict, "builtins")
1145
1146
dict.__class_getitem__ = _b_.classmethod.$factory(dict.__class_getitem__)
1147
1148
$B.empty_dict = function(){
1149
return {
1150
__class__: dict,
1151
$numeric_dict : {},
1152
$object_dict : {},
1153
$string_dict : {},
1154
$str_hash: {},
1155
$version: 0,
1156
$order: 0
1160
// This must be done after set_func_names, otherwise dict.fromkeys doesn't
1161
// have the attribute $infos
1162
dict.fromkeys = _b_.classmethod.$factory(dict.fromkeys)
1163
1164
$B.getset_descriptor = $B.make_class("getset_descriptor",
1165
function(klass, attr){
1166
return {
1167
__class__: $B.getset_descriptor,
1168
__doc__: _b_.None,
1169
cls: klass,
1170
attr: attr
1171
}
1172
}
1173
)
1174
1175
$B.getset_descriptor.__repr__ = $B.getset_descriptor.__str__ = function(self){
1176
return `<attribute '${self.attr}' of '${self.cls.$infos.__name__}' objects>`
1177
}
1178
1179
$B.set_func_names($B.getset_descriptor, "builtins")
1180
1181
// Class for attribute __dict__ of classes
1182
var mappingproxy = $B.mappingproxy = $B.make_class("mappingproxy",
Feb 12, 2018
1183
function(obj){
1184
if(_b_.isinstance(obj, dict)){
1185
// obj is a dictionary, with $string_dict table such that
1186
// obj.$string_dict[key] = [value, rank]
1187
// Transform it into an object with attribute $jsobj such that
1188
// res.$jsobj[key] = value
1189
var res = $B.obj_dict(dict.$to_obj(obj))
1190
}else{
1191
var res = $B.obj_dict(obj)
1192
}
Feb 12, 2018
1193
res.__class__ = mappingproxy
1194
return res
1195
}
1196
)
1198
mappingproxy.$match_mapping_pattern = true // for pattern matching (PEP 634)
1199
1200
mappingproxy.__repr__ = function(){
1201
return '<mappingproxy object>'
1202
}
1203
Feb 12, 2018
1204
mappingproxy.__setitem__ = function(){
Mar 7, 2018
1205
throw _b_.TypeError.$factory("'mappingproxy' object does not support " +
1206
"item assignment")
1209
for(var attr in dict){
1210
if(mappingproxy[attr] !== undefined ||
1211
["__class__", "__mro__", "__new__", "__init__", "__delitem__",
1212
"clear", "fromkeys", "pop", "popitem", "setdefault",
1213
"update"].indexOf(attr) > -1){
1214
continue
1215
}
1216
if(typeof dict[attr] == "function"){
1217
mappingproxy[attr] = (function(key){
1218
return function(){
1219
return dict[key].apply(null, arguments)
1220
}
1221
})(attr)
1222
}else{
1223
mappingproxy[attr] = dict[attr]
1224
}
1225
}
1226
Feb 12, 2018
1227
$B.set_func_names(mappingproxy, "builtins")
1229
function jsobj2dict(x, exclude){
1230
exclude = exclude || function(){return false}
1233
if(attr.charAt(0) != "$" && ! exclude(attr)){
1234
if(x[attr] === null){
1235
d.$string_dict[attr] = [_b_.None, d.$order++]
1236
}else if(x[attr] === undefined){
1237
continue
1238
}else if(x[attr].$jsobj === x){
1239
d.$string_dict[attr] = [d, d.$order++]
1241
d.$string_dict[attr] = [$B.$JS2Py(x[attr]), d.$order++]
1243
}
1244
}
1245
return d
1246
}
1248
$B.obj_dict = function(obj, exclude){
1249
var klass = obj.__class__ || $B.get_class(obj)
1250
if(klass !== undefined && klass.$native){
1251
throw $B.attr_error("__dict__", obj)
1252
}
1254
res.$jsobj = obj
1255
res.$exclude = exclude || function(){return false}
1256
return res
1257
}
1258
1259
// Wrapper around a JS object to handle it as a Python dictionary.
1260
// Some keys of the original object can be ignored by passing
1261
// the filtering function exclude().
1262
// Supports adding new keys.
1263
1264
var jsobj_as_pydict = $B.jsobj_as_pydict = $B.make_class('jsobj_as_pydict',
1265
function(jsobj, exclude){
1266
return {
1267
__class__: jsobj_as_pydict,
1268
obj: jsobj,
1269
exclude: exclude ? exclude : function(){return false},
1270
new_keys: []
1271
}
1272
}
1273
)
1274
1275
jsobj_as_pydict.__contains__ = function(self, key){
1276
if(self.new_keys.indexOf(key) > -1){
1277
return true
1278
}
1279
return ! (self.exclude(key) || self.obj[key] === undefined)
1280
}
1281
1282
jsobj_as_pydict.__delitem__ = function(self, key){
1283
jsobj_as_pydict.__getitem__(self, key) // raises KeyError if not present
1284
delete self.obj[key]
1285
var ix = self.new_keys.indexOf(key)
1286
if(ix > -1){
1287
self.new_keys.splice(ix, 1)
1288
}
1289
}
1290
1291
jsobj_as_pydict.__eq__ = function(self, other){
1292
if(other.__class__ !== jsobj_as_pydict){
1293
return _b_.NotImplemented
1294
}
1295
// create true Python dicts with the items in self and other
1296
var self1 = $B.empty_dict()
1297
other1 = $B.empty_dict()
1298
1299
dict.__init__(self1, jsobj_as_pydict.items(self))
1300
dict.__init__(other1, jsobj_as_pydict.items(other))
1301
1302
// Compare true Python dicts
1303
return dict.__eq__(self1, other1)
1304
}
1305
1306
jsobj_as_pydict.__getitem__ = function(self, key){
1307
if(jsobj_as_pydict.__contains__(self, key)){
1308
return self.obj[key]
1309
}
1310
throw _b_.KeyError.$factory(key)
1311
}
1312
1313
jsobj_as_pydict.__iter__ = function(self){
1314
return _b_.iter(jsobj_as_pydict.keys(self))
1315
}
1316
1317
jsobj_as_pydict.__len__ = function(self){
1318
var len = 0
1319
for(var key in self.obj){
1320
if(! self.exclude(key)){
1321
len++
1322
}
1323
}
1324
return len + self.new_keys.length
1325
}
1326
1327
jsobj_as_pydict.__repr__ = function(self){
1328
if($B.repr.enter(self)){
1329
return "{...}"
1330
}
1331
var res = [],
1332
items = _b_.list.$factory(jsobj_as_pydict.items(self))
1333
for(var item of items){
1334
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
1335
}
1336
$B.repr.leave(self)
1337
return "{" + res.join(", ") + "}"
1338
}
1339
1340
jsobj_as_pydict.__setitem__ = function(self, key, value){
1341
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1342
self.new_keys.push(key)
1343
}
1344
self.obj[key] = value
1345
}
1346
1347
jsobj_as_pydict.get = function(self, key, _default){
1348
_default = _default === undefined ? _b_.None : _default
1349
if(self.exclude(key) || self.obj[key] === undefined){
1350
return _default
1351
}
1352
return self.obj[key]
1353
}
1354
1355
jsobj_as_pydict.items = function(self){
1356
var items = []
1357
for(var key in self.obj){
1358
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1359
continue
1360
}
1361
items.push($B.fast_tuple([key, self.obj[key]]))
1362
}
1363
var set_like = true
1364
// Check if all values are hashable
1365
for(var item of items){
1366
try{
1367
_b_.hash(item[1])
1368
}catch(err){
1369
set_like = false
1370
break
1371
}
1373
var it = dict_items.$factory(self, items, set_like)
1374
it.dict_version = self.$version
1375
return it
1376
}
1377
1378
jsobj_as_pydict.keys = function(self){
1379
var lst = []
1380
for(var key in self.obj){
1381
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1382
continue
1383
}
1384
lst.push(key)
1385
}
1386
var it = dict_keys.$factory(self, lst, true)
1387
it.dict_version = self.$version
1388
return it
1389
}
1390
1391
jsobj_as_pydict.values = function(self){
1392
var values = []
1393
for(var key in self.obj){
1394
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1395
continue
1396
}
1397
values.push(self.obj[key])
1399
var it = dict_values.$factory(self, values, false)
1400
it.dict_version = self.$version
1401
return it
1402
}
1403
1404
$B.set_func_names(jsobj_as_pydict, 'builtins')
1405
Sep 5, 2014
1406
})(__BRYTHON__)