Skip to content
Permalink
Newer
Older
100644 1402 lines (1265 sloc) 40.6 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
Feb 12, 2018
1200
mappingproxy.__setitem__ = function(){
Mar 7, 2018
1201
throw _b_.TypeError.$factory("'mappingproxy' object does not support " +
1202
"item assignment")
1205
for(var attr in dict){
1206
if(mappingproxy[attr] !== undefined ||
1207
["__class__", "__mro__", "__new__", "__init__", "__delitem__",
1208
"clear", "fromkeys", "pop", "popitem", "setdefault",
1209
"update"].indexOf(attr) > -1){
1210
continue
1211
}
1212
if(typeof dict[attr] == "function"){
1213
mappingproxy[attr] = (function(key){
1214
return function(){
1215
return dict[key].apply(null, arguments)
1216
}
1217
})(attr)
1218
}else{
1219
mappingproxy[attr] = dict[attr]
1220
}
1221
}
1222
Feb 12, 2018
1223
$B.set_func_names(mappingproxy, "builtins")
1225
function jsobj2dict(x, exclude){
1226
exclude = exclude || function(){return false}
1229
if(attr.charAt(0) != "$" && ! exclude(attr)){
1230
if(x[attr] === null){
1231
d.$string_dict[attr] = [_b_.None, d.$order++]
1232
}else if(x[attr] === undefined){
1233
continue
1234
}else if(x[attr].$jsobj === x){
1235
d.$string_dict[attr] = [d, d.$order++]
1237
d.$string_dict[attr] = [$B.$JS2Py(x[attr]), d.$order++]
1239
}
1240
}
1241
return d
1242
}
1244
$B.obj_dict = function(obj, exclude){
1245
var klass = obj.__class__ || $B.get_class(obj)
1246
if(klass !== undefined && klass.$native){
1247
throw $B.attr_error("__dict__", obj)
1248
}
1250
res.$jsobj = obj
1251
res.$exclude = exclude || function(){return false}
1252
return res
1253
}
1254
1255
// Wrapper around a JS object to handle it as a Python dictionary.
1256
// Some keys of the original object can be ignored by passing
1257
// the filtering function exclude().
1258
// Supports adding new keys.
1259
1260
var jsobj_as_pydict = $B.jsobj_as_pydict = $B.make_class('jsobj_as_pydict',
1261
function(jsobj, exclude){
1262
return {
1263
__class__: jsobj_as_pydict,
1264
obj: jsobj,
1265
exclude: exclude ? exclude : function(){return false},
1266
new_keys: []
1267
}
1268
}
1269
)
1270
1271
jsobj_as_pydict.__contains__ = function(self, key){
1272
if(self.new_keys.indexOf(key) > -1){
1273
return true
1274
}
1275
return ! (self.exclude(key) || self.obj[key] === undefined)
1276
}
1277
1278
jsobj_as_pydict.__delitem__ = function(self, key){
1279
jsobj_as_pydict.__getitem__(self, key) // raises KeyError if not present
1280
delete self.obj[key]
1281
var ix = self.new_keys.indexOf(key)
1282
if(ix > -1){
1283
self.new_keys.splice(ix, 1)
1284
}
1285
}
1286
1287
jsobj_as_pydict.__eq__ = function(self, other){
1288
if(other.__class__ !== jsobj_as_pydict){
1289
return _b_.NotImplemented
1290
}
1291
// create true Python dicts with the items in self and other
1292
var self1 = $B.empty_dict()
1293
other1 = $B.empty_dict()
1294
1295
dict.__init__(self1, jsobj_as_pydict.items(self))
1296
dict.__init__(other1, jsobj_as_pydict.items(other))
1297
1298
// Compare true Python dicts
1299
return dict.__eq__(self1, other1)
1300
}
1301
1302
jsobj_as_pydict.__getitem__ = function(self, key){
1303
if(jsobj_as_pydict.__contains__(self, key)){
1304
return self.obj[key]
1305
}
1306
throw _b_.KeyError.$factory(key)
1307
}
1308
1309
jsobj_as_pydict.__iter__ = function(self){
1310
return _b_.iter(jsobj_as_pydict.keys(self))
1311
}
1312
1313
jsobj_as_pydict.__len__ = function(self){
1314
var len = 0
1315
for(var key in self.obj){
1316
if(! self.exclude(key)){
1317
len++
1318
}
1319
}
1320
return len + self.new_keys.length
1321
}
1322
1323
jsobj_as_pydict.__repr__ = function(self){
1324
if($B.repr.enter(self)){
1325
return "{...}"
1326
}
1327
var res = [],
1328
items = _b_.list.$factory(jsobj_as_pydict.items(self))
1329
for(var item of items){
1330
res.push(_b_.repr(item[0]) + ": " + _b_.repr(item[1]))
1331
}
1332
$B.repr.leave(self)
1333
return "{" + res.join(", ") + "}"
1334
}
1335
1336
jsobj_as_pydict.__setitem__ = function(self, key, value){
1337
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1338
self.new_keys.push(key)
1339
}
1340
self.obj[key] = value
1341
}
1342
1343
jsobj_as_pydict.get = function(self, key, _default){
1344
_default = _default === undefined ? _b_.None : _default
1345
if(self.exclude(key) || self.obj[key] === undefined){
1346
return _default
1347
}
1348
return self.obj[key]
1349
}
1350
1351
jsobj_as_pydict.items = function(self){
1352
var items = []
1353
for(var key in self.obj){
1354
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1355
continue
1356
}
1357
items.push($B.fast_tuple([key, self.obj[key]]))
1358
}
1359
var set_like = true
1360
// Check if all values are hashable
1361
for(var item of items){
1362
try{
1363
_b_.hash(item[1])
1364
}catch(err){
1365
set_like = false
1366
break
1367
}
1369
var it = dict_items.$factory(self, items, set_like)
1370
it.dict_version = self.$version
1371
return it
1372
}
1373
1374
jsobj_as_pydict.keys = function(self){
1375
var lst = []
1376
for(var key in self.obj){
1377
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1378
continue
1379
}
1380
lst.push(key)
1381
}
1382
var it = dict_keys.$factory(self, lst, true)
1383
it.dict_version = self.$version
1384
return it
1385
}
1386
1387
jsobj_as_pydict.values = function(self){
1388
var values = []
1389
for(var key in self.obj){
1390
if(self.exclude(key) && self.new_keys.indexOf(key) == -1){
1391
continue
1392
}
1393
values.push(self.obj[key])
1395
var it = dict_values.$factory(self, values, false)
1396
it.dict_version = self.$version
1397
return it
1398
}
1399
1400
$B.set_func_names(jsobj_as_pydict, 'builtins')
1401
Sep 5, 2014
1402
})(__BRYTHON__)