Skip to content
Permalink
Newer
Older
100644 2805 lines (2591 sloc) 85.1 KB
Sep 5, 2014
1
;(function($B){
2
3
var _b_ = $B.builtins
Sep 5, 2014
4
5
// build tables from data in unicode_data.js
6
var unicode_tables = $B.unicode_tables
Sep 5, 2014
7
8
9
$B.has_surrogate = function(s){
10
// Check if there are "surrogate pairs" characters in string s
11
for(var i = 0; i < s.length; i++){
12
code = s.charCodeAt(i)
13
if(code >= 0xD800 && code <= 0xDBFF){
14
return true
15
}
16
}
17
return false
18
}
19
str
Feb 10, 2018
20
var str = {
Mar 19, 2018
21
__class__: _b_.type,
22
__dir__: _b_.object.__dir__,
23
$infos: {
24
__module__: "builtins",
25
__name__: "str"
26
},
str
Feb 10, 2018
27
$is_class: true,
Mar 19, 2018
28
$native: true
Sep 5, 2014
29
}
30
Mar 19, 2018
32
if($.start === null || $.start === _b_.None){$.start = 0}
33
else if($.start < 0){
34
$.start += $.self.length
35
$.start = Math.max(0, $.start)
36
}
37
if($.end === null || $.end === _b_.None){$.end = $.self.length}
38
else if($.end < 0){
39
$.end += $.self.length
40
$.end = Math.max(0, $.end)
41
}
43
if(! _b_.isinstance($.start, _b_.int) || ! _b_.isinstance($.end, _b_.int)){
Mar 19, 2018
44
throw _b_.TypeError.$factory("slice indices must be integers " +
45
"or None or have an __index__ method")
46
}
49
function reverse(s){
50
// Reverse a string
Mar 19, 2018
51
return s.split("").reverse().join("")
52
}
53
54
function check_str(obj, prefix){
Mar 19, 2018
55
if(! _b_.isinstance(obj, str)){
56
throw _b_.TypeError.$factory((prefix || '') +
57
"must be str, not " + $B.class_name(obj))
Mar 19, 2018
58
}
61
function to_chars(s){
62
// Transform Javascript string s into a list of Python characters
63
// (2 JS chars if surrogate, 1 otherwise)
64
var chars = []
65
for(var i = 0, len = s.length; i < len; i++){
66
var code = s.charCodeAt(i)
67
if(code >= 0xD800 && code <= 0xDBFF){
68
chars.push(s.substr(i, 2))
69
i++
70
}else{
71
chars.push(s.charAt(i))
72
}
73
}
74
return chars
75
}
76
77
function to_codepoints(s){
78
// Transform Javascript string s into a list of codepoints
79
var cps = []
80
for(var i = 0, len = s.length; i < len; i++){
81
var code = s.charCodeAt(i)
82
if(code >= 0xD800 && code <= 0xDBFF){
83
var v = 0x10000
84
v += (code & 0x03FF) << 10
85
v += (s.charCodeAt(i + 1) & 0x03FF)
86
cps.push(v)
87
i++
88
}else{
89
cps.push(code)
90
}
91
}
92
return cps
93
}
94
95
str.__add__ = function(self, other){
Mar 19, 2018
96
if(!(typeof other === "string")){
97
try{return $B.$getattr(other, "__radd__")(self)}
Mar 19, 2018
98
catch(err){
99
throw _b_.TypeError.$factory("Can't convert " +
100
$B.class_name(other) + " to str implicitly")}
Sep 5, 2014
101
}
Mar 19, 2018
102
return self + other
Sep 5, 2014
103
}
104
Mar 19, 2018
105
str.__contains__ = function(self, item){
106
if(! _b_.isinstance(item, str)){
Mar 19, 2018
107
throw _b_.TypeError.$factory("'in <string>' requires " +
108
"string as left operand, not " + item.__class__)
109
}
110
if(typeof item == "string"){
111
var nbcar = item.length
112
}else{
113
var nbcar = _b_.len(item)
114
}
115
if(nbcar == 0){
116
// a string contains the empty string
117
return true
118
}
119
if(self.length == 0){
120
return nbcar == 0
121
}
Mar 19, 2018
122
for(var i = 0, len = self.length; i < len; i++){
123
if(self.substr(i, nbcar) == item){
124
return true
125
}
Sep 5, 2014
126
}
127
return false
128
}
129
str
Feb 10, 2018
130
str.__delitem__ = function(){
131
throw _b_.TypeError.$factory("'str' object doesn't support item deletion")
Sep 5, 2014
132
}
133
Mar 19, 2018
134
// __dir__must be assigned explicitely because attribute resolution for
135
// builtin classes doesn't use __mro__
136
str.__dir__ = _b_.object.__dir__
138
str.__eq__ = function(self, other){
Mar 23, 2018
139
if(_b_.isinstance(other, _b_.str)){
140
return other.valueOf() == self.valueOf()
141
}
142
return _b_.NotImplemented
Sep 5, 2014
143
}
144
145
function preformat(self, fmt){
str
Feb 10, 2018
146
if(fmt.empty){return _b_.str.$factory(self)}
Mar 19, 2018
147
if(fmt.type && fmt.type != "s"){
148
throw _b_.ValueError.$factory("Unknown format code '" + fmt.type +
149
"' for object of type 'str'")
151
return self
152
}
153
str
Feb 10, 2018
154
str.__format__ = function(self, format_spec) {
155
var fmt = new $B.parse_format_spec(format_spec)
Mar 19, 2018
156
if(fmt.sign !== undefined){
157
throw _b_.ValueError.$factory(
158
"Sign not allowed in string format specifier")
160
if(fmt.precision){
161
self = self.substr(0, fmt.precision)
162
}
163
// For strings, alignment default to left
Mar 19, 2018
164
fmt.align = fmt.align || "<"
165
return $B.format_width(preformat(self, fmt), fmt)
Sep 5, 2014
166
}
167
168
str.__getitem__ = function(self, arg){
169
var chars = to_chars(self)
170
if(_b_.isinstance(arg, _b_.int)){
Sep 5, 2014
171
var pos = arg
172
if(arg < 0){
173
pos += self.length
174
}
175
if(pos >= 0 && pos < chars.length){
176
return chars[pos]
177
}
Mar 19, 2018
178
throw _b_.IndexError.$factory("string index out of range")
179
}
180
if(_b_.isinstance(arg, _b_.slice)){
Mar 19, 2018
181
var s = _b_.slice.$conv_for_seq(arg, self.length),
182
start = s.start,
183
stop = s.stop,
184
step = s.step
185
var res = "",
Mar 19, 2018
186
i = null
Mar 19, 2018
187
if(step > 0){
188
if(stop <= start){
189
return ""
190
}
191
for(var i = start; i < stop; i += step){
192
res += chars[i]
193
}
Mar 23, 2018
194
}else{
195
if(stop >= start){
196
return ''
197
}
198
for(var i = start; i > stop; i += step){
199
res += chars[i]
200
}
Sep 5, 2014
202
return res
203
}
204
if(_b_.isinstance(arg, _b_.bool)){
205
return self.__getitem__(_b_.int.$factory(arg))
206
}
Mar 19, 2018
207
throw _b_.TypeError.$factory("string indices must be integers")
Sep 5, 2014
208
}
209
210
var prefix = 2,
211
suffix = 3,
Jun 12, 2020
212
mask = (2 ** 32 - 1),
213
str_hash_cache = {}
214
215
str.$nb_str_hash_cache = 0
Jun 12, 2020
216
217
function fnv(p){
218
if(p.length == 0){
219
return 0
220
}
Sep 5, 2014
221
222
var x = prefix
223
x = (x ^ (p[0] << 7)) & mask
224
for(var i = 0, len = p.length; i < len; i++){
225
x = ((1000003 * x) ^ p[i]) & mask
226
}
227
x = (x ^ p.length) & mask
228
x = (x ^ suffix) & mask
Sep 5, 2014
229
230
if(x == -1){
231
x = -2
232
}
233
return x
234
}
236
str.__hash__ = function(self) {
Jun 12, 2020
237
if(str_hash_cache[self] !== undefined){
238
return str_hash_cache[self]
239
}
240
str.$nb_str_hash_cache++
241
if(str.$nb_str_hash_cache > 100000){
242
// Avoid memory overflow
243
str.$nb_str_hash_cache = 0
244
str_hash_cache = {}
245
}
246
return str_hash_cache[self] = fnv(to_codepoints(self))
Sep 5, 2014
247
}
248
Mar 19, 2018
249
str.__init__ = function(self, arg){
Sep 5, 2014
250
self.valueOf = function(){return arg}
251
self.toString = function(){return arg}
Sep 5, 2014
253
}
254
255
var str_iterator = $B.make_iterator_class("str_iterator")
str
Feb 10, 2018
256
str.__iter__ = function(self){
257
return str_iterator.$factory(to_chars(self))
Sep 5, 2014
258
}
259
260
str.__len__ = function(self){
261
// found at
262
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length
263
return [...self].length
Sep 5, 2014
265
266
// Start of section for legacy formatting (with %)
267
Mar 19, 2018
268
var kwarg_key = new RegExp("([^\\)]*)\\)")
269
270
var NotANumber = function() {
Mar 19, 2018
271
this.name = "NotANumber"
272
}
273
Mar 19, 2018
274
var number_check = function(s){
275
if(! _b_.isinstance(s, [_b_.int, _b_.float])){
276
throw new NotANumber()
277
}
278
}
279
Mar 19, 2018
280
var get_char_array = function(size, char){
281
if(size <= 0){
282
return ""
283
}
284
return new Array(size + 1).join(char)
285
}
286
Mar 19, 2018
287
var format_padding = function(s, flags, minus_one){
288
var padding = flags.padding
Mar 23, 2018
289
if(! padding){ // undefined
290
return s
291
}
292
s = s.toString()
293
padding = parseInt(padding, 10)
Mar 23, 2018
294
if(minus_one){ // numeric formatting where sign goes in front of padding
295
padding -= 1
296
}
Mar 19, 2018
297
if(! flags.left){
298
return get_char_array(padding - s.length, flags.pad_char) + s
Mar 19, 2018
299
}else{
300
// left adjusted
301
return s + get_char_array(padding - s.length, flags.pad_char)
302
}
303
}
304
Mar 19, 2018
305
var format_int_precision = function(val, flags){
306
var precision = flags.precision
Mar 19, 2018
307
if(!precision){
308
return val.toString()
309
}
310
precision = parseInt(precision, 10)
Mar 19, 2018
312
if(val.__class__ === $B.long_int){
313
s = $B.long_int.to_base(val, 10)
314
}else{
315
s = val.toString()
Mar 19, 2018
317
if(s[0] === "-"){
318
return "-" + get_char_array(precision - s.length + 1, "0") + s.slice(1)
Mar 19, 2018
320
return get_char_array(precision - s.length, "0") + s
321
}
322
Mar 19, 2018
323
var format_float_precision = function(val, upper, flags, modifier){
324
var precision = flags.precision
325
// val is a float
Mar 19, 2018
326
if(isFinite(val)){
327
return modifier(val, precision, flags, upper)
Mar 19, 2018
329
if(val === Infinity){
330
val = "inf"
331
}else if(val === -Infinity){
332
val = "-inf"
333
}else{
334
val = "nan"
Mar 19, 2018
336
if(upper){
337
return val.toUpperCase()
338
}
339
return val
341
}
342
Mar 19, 2018
343
var format_sign = function(val, flags){
344
if(flags.sign){
345
if(val >= 0){
346
return "+"
Sep 5, 2014
347
}
Mar 19, 2018
348
}else if (flags.space){
349
if(val >= 0){
350
return " "
351
}
352
}
353
return ""
354
}
Sep 5, 2014
355
356
var str_format = function(val, flags) {
357
// string format supports left and right padding
358
flags.pad_char = " " // even if 0 padding is defined, don't use it
str
Feb 10, 2018
359
return format_padding(str.$factory(val), flags)
Sep 5, 2014
361
362
var num_format = function(val, flags) {
363
number_check(val)
Mar 19, 2018
364
if(val.__class__ === $B.long_int){
365
val = $B.long_int.to_base(val, 10)
366
}else{
367
val = parseInt(val)
370
var s = format_int_precision(val, flags)
Mar 19, 2018
371
if(flags.pad_char === "0"){
372
if(val < 0){
373
s = s.substring(1)
Mar 19, 2018
374
return "-" + format_padding(s, flags, true)
375
}
376
var sign = format_sign(val, flags)
Mar 19, 2018
377
if(sign !== ""){
378
return sign + format_padding(s, flags, true)
379
}
380
}
382
return format_padding(format_sign(val, flags) + s, flags)
383
}
Sep 5, 2014
384
385
var repr_format = function(val, flags) {
386
flags.pad_char = " " // even if 0 padding is defined, don't use it
387
return format_padding(_b_.repr(val), flags)
Sep 5, 2014
389
390
var ascii_format = function(val, flags) {
391
flags.pad_char = " " // even if 0 padding is defined, don't use it
392
return format_padding(_b_.ascii(val), flags)
Sep 5, 2014
394
395
// converts val to float and sets precision if missing
Mar 19, 2018
396
var _float_helper = function(val, flags){
397
number_check(val)
Mar 19, 2018
398
if(! flags.precision){
399
if(! flags.decimal_point){
400
flags.precision = 6
Mar 19, 2018
401
}else{
402
flags.precision = 0
403
}
Mar 19, 2018
404
}else{
405
flags.precision = parseInt(flags.precision, 10)
406
validate_precision(flags.precision)
407
}
408
return parseFloat(val)
409
}
Sep 5, 2014
410
411
// used to capture and remove trailing zeroes
Mar 19, 2018
412
var trailing_zeros = /(.*?)(0+)([eE].*)/,
413
leading_zeros = /\.(0*)/,
414
trailing_dot = /\.$/
Sep 5, 2014
415
416
var validate_precision = function(precision) {
417
// force precision to limits of javascript
Mar 19, 2018
418
if(precision > 20){precision = 20}
419
}
420
421
// gG
Mar 19, 2018
422
var floating_point_format = function(val, upper, flags){
423
val = _float_helper(val, flags),
424
v = val.toString(),
425
v_len = v.length,
426
dot_idx = v.indexOf('.')
427
if(dot_idx < 0){dot_idx = v_len}
428
if(val < 1 && val > -1){
429
var zeros = leading_zeros.exec(v),
430
numzeros
431
if(zeros){
432
numzeros = zeros[1].length
Mar 19, 2018
433
}else{
434
numzeros = 0
435
}
Mar 19, 2018
436
if(numzeros >= 4){
437
val = format_sign(val, flags) + format_float_precision(val, upper,
438
flags, _floating_g_exp_helper)
439
if(!flags.alternate){
440
var trl = trailing_zeros.exec(val)
Mar 19, 2018
441
if(trl){
442
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
444
}else{
445
if(flags.precision <= 1){
446
val = val[0] + "." + val.substring(1)
448
}
449
return format_padding(val, flags)
450
}
451
flags.precision = (flags.precision || 0) + numzeros
Mar 19, 2018
452
return format_padding(format_sign(val, flags) +
453
format_float_precision(val, upper, flags,
454
function(val, precision) {
455
return val.toFixed(_b_.min(precision, v_len - dot_idx) +
Mar 19, 2018
456
numzeros)
457
}),
458
flags
459
)
460
}
461
462
if(dot_idx > flags.precision){
463
val = format_sign(val, flags) + format_float_precision(val, upper,
464
flags, _floating_g_exp_helper)
465
if(! flags.alternate){
466
var trl = trailing_zeros.exec(val)
Mar 19, 2018
467
if(trl){
468
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
470
}else{
471
if(flags.precision <= 1){
472
val = val[0] + "." + val.substring(1)
473
}
474
}
475
return format_padding(val, flags)
476
}
Mar 19, 2018
477
return format_padding(format_sign(val, flags) +
478
format_float_precision(val, upper, flags,
479
function(val, precision) {
480
if(!flags.decimal_point){
481
precision = _b_.min(v_len - 1, 6)
Mar 19, 2018
482
}else if (precision > v_len){
483
if(! flags.alternate){
484
precision = v_len
485
}
Sep 5, 2014
486
}
Mar 19, 2018
487
if(precision < dot_idx){
488
precision = dot_idx
489
}
490
return val.toFixed(precision - dot_idx)
491
}),
492
flags
493
)
Sep 5, 2014
495
Mar 19, 2018
496
var _floating_g_exp_helper = function(val, precision, flags, upper){
497
if(precision){--precision}
498
val = val.toExponential(precision)
499
// pad exponent to two digits
Mar 19, 2018
500
var e_idx = val.lastIndexOf("e")
501
if(e_idx > val.length - 4){
502
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
504
if(upper){return val.toUpperCase()}
505
return val
506
}
507
508
// fF
509
var floating_point_decimal_format = function(val, upper, flags) {
510
val = _float_helper(val, flags)
Mar 19, 2018
511
return format_padding(format_sign(val, flags) +
512
format_float_precision(val, upper, flags,
513
function(val, precision, flags) {
514
val = val.toFixed(precision)
515
if(precision === 0 && flags.alternate){
516
val += '.'
517
}
518
return val
519
}),
520
flags
521
)
522
}
523
524
var _floating_exp_helper = function(val, precision, flags, upper) {
525
val = val.toExponential(precision)
526
// pad exponent to two digits
Mar 19, 2018
527
var e_idx = val.lastIndexOf("e")
Mar 23, 2018
528
if(e_idx > val.length - 4){
Mar 19, 2018
529
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
531
if(upper){return val.toUpperCase()}
532
return val
533
}
534
535
// eE
Mar 19, 2018
536
var floating_point_exponential_format = function(val, upper, flags){
537
val = _float_helper(val, flags)
Mar 19, 2018
539
return format_padding(format_sign(val, flags) +
540
format_float_precision(val, upper, flags, _floating_exp_helper), flags)
541
}
542
Mar 19, 2018
543
var signed_hex_format = function(val, upper, flags){
545
number_check(val)
Mar 23, 2018
547
if(val.__class__ === $B.long_int){
Mar 19, 2018
548
ret = $B.long_int.to_base(val, 16)
549
}else{
550
ret = parseInt(val)
551
ret = ret.toString(16)
552
}
553
ret = format_int_precision(ret, flags)
Mar 19, 2018
554
if(upper){ret = ret.toUpperCase()}
Mar 23, 2018
555
if(flags.pad_char === "0"){
Mar 19, 2018
556
if(val < 0){
557
ret = ret.substring(1)
Mar 19, 2018
558
ret = "-" + format_padding(ret, flags, true)
559
}
560
var sign = format_sign(val, flags)
Mar 19, 2018
561
if(sign !== ""){
562
ret = sign + format_padding(ret, flags, true)
Sep 5, 2014
563
}
Mar 19, 2018
566
if(flags.alternate){
567
if(ret.charAt(0) === "-"){
568
if(upper){ret = "-0X" + ret.slice(1)}
569
else{ret = "-0x" + ret.slice(1)}
570
}else{
571
if(upper){ret = "0X" + ret}
572
else{ret = "0x" + ret}
573
}
574
}
575
return format_padding(format_sign(val, flags) + ret, flags)
576
}
Sep 5, 2014
577
578
var octal_format = function(val, flags) {
579
number_check(val)
Mar 19, 2018
582
if(val.__class__ === $B.long_int){
583
ret = $B.long_int.to_base(8)
584
}else{
585
ret = parseInt(val)
586
ret = ret.toString(8)
589
ret = format_int_precision(ret, flags)
Mar 19, 2018
591
if(flags.pad_char === "0"){
592
if(val < 0){
593
ret = ret.substring(1)
Mar 19, 2018
594
ret = "-" + format_padding(ret, flags, true)
595
}
596
var sign = format_sign(val, flags)
Mar 19, 2018
597
if(sign !== ""){
598
ret = sign + format_padding(ret, flags, true)
599
}
Sep 5, 2014
600
}
Mar 19, 2018
602
if(flags.alternate){
603
if(ret.charAt(0) === "-"){ret = "-0o" + ret.slice(1)}
604
else{ret = "0o" + ret}
Sep 5, 2014
605
}
606
return format_padding(ret, flags)
607
}
608
609
function series_of_bytes(val, flags){
610
if(val.__class__ && val.__class__.$buffer_protocol){
611
var it = _b_.iter(val),
612
ints = []
613
while(true){
614
try{
615
ints.push(_b_.next(it))
616
}catch(err){
617
if(err.__class__ === _b_.StopIteration){
618
var b = _b_.bytes.$factory(ints)
619
return format_padding(_b_.bytes.decode(b, "ascii"), flags)
620
}
621
throw err
622
}
623
}
624
}else{
625
try{
626
bytes_obj = $B.$getattr(val, "__bytes__")
627
return format_padding(_b_.bytes.decode(bytes_obj), flags)
628
}catch(err){
629
if(err.__class__ === _b_.AttributeError){
630
throw _b_.TypeError.$factory("%b does not accept '" +
631
$B.class_name(val) + "'")
632
}
633
throw err
634
}
635
}
636
}
637
Mar 19, 2018
638
var single_char_format = function(val, flags){
639
if(_b_.isinstance(val, str) && val.length == 1){
641
}else if(_b_.isinstance(val, _b_.bytes) && val.source.length == 1){
642
val = val.source[0]
643
}else{
644
try{
645
val = _b_.int.$factory(val) // yes, floats are valid (they are cast to int)
646
}catch (err){
647
throw _b_.TypeError.$factory("%c requires int or char")
648
}
650
return format_padding(_b_.chr(val), flags)
651
}
652
Mar 19, 2018
653
var num_flag = function(c, flags){
654
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
655
flags.pad_char = "0"
656
return
657
}
Mar 19, 2018
658
if(!flags.decimal_point){
659
flags.padding = (flags.padding || "") + c
Mar 19, 2018
660
}else{
661
flags.precision = (flags.precision || "") + c
662
}
663
}
664
665
var decimal_point_flag = function(val, flags) {
Mar 23, 2018
666
if(flags.decimal_point){
667
// can only have one decimal point
668
throw new UnsupportedChar()
669
}
670
flags.decimal_point = true
671
}
672
Mar 19, 2018
673
var neg_flag = function(val, flags){
674
flags.pad_char = " " // overrides '0' flag
675
flags.left = true
676
}
677
Mar 19, 2018
678
var space_flag = function(val, flags){
679
flags.space = true
680
}
681
Mar 19, 2018
682
var sign_flag = function(val, flags){
683
flags.sign = true
684
}
685
Mar 19, 2018
686
var alternate_flag = function(val, flags){
687
flags.alternate = true
688
}
689
690
var char_mapping = {
Mar 19, 2018
692
"s": str_format,
693
"d": num_format,
694
"i": num_format,
695
"u": num_format,
696
"o": octal_format,
697
"r": repr_format,
698
"a": ascii_format,
699
"g": function(val, flags){
700
return floating_point_format(val, false, flags)
701
},
702
"G": function(val, flags){return floating_point_format(val, true, flags)},
703
"f": function(val, flags){
704
return floating_point_decimal_format(val, false, flags)
705
},
706
"F": function(val, flags){
707
return floating_point_decimal_format(val, true, flags)
708
},
709
"e": function(val, flags){
710
return floating_point_exponential_format(val, false, flags)
711
},
712
"E": function(val, flags){
713
return floating_point_exponential_format(val, true, flags)
714
},
715
"x": function(val, flags){return signed_hex_format(val, false, flags)},
716
"X": function(val, flags){return signed_hex_format(val, true, flags)},
717
"c": single_char_format,
718
"0": function(val, flags){return num_flag("0", flags)},
719
"1": function(val, flags){return num_flag("1", flags)},
720
"2": function(val, flags){return num_flag("2", flags)},
721
"3": function(val, flags){return num_flag("3", flags)},
722
"4": function(val, flags){return num_flag("4", flags)},
723
"5": function(val, flags){return num_flag("5", flags)},
724
"6": function(val, flags){return num_flag("6", flags)},
725
"7": function(val, flags){return num_flag("7", flags)},
726
"8": function(val, flags){return num_flag("8", flags)},
727
"9": function(val, flags){return num_flag("9", flags)},
728
"-": neg_flag,
729
" ": space_flag,
730
"+": sign_flag,
731
".": decimal_point_flag,
732
"#": alternate_flag
733
}
734
735
// exception thrown when an unsupported char is encountered in legacy format
Mar 19, 2018
736
var UnsupportedChar = function(){
737
this.name = "UnsupportedChar"
738
}
739
740
str.__mod__ = function(self, args){
741
var length = self.length,
Mar 19, 2018
742
pos = 0 | 0,
743
argpos = null,
744
getitem
Mar 19, 2018
745
if(_b_.isinstance(args, _b_.tuple)){
746
argpos = 0 | 0
748
getitem = $B.$getattr(args, "__getitem__", _b_.None)
749
}
750
var ret = ''
751
var $get_kwarg_string = function(s) {
752
// returns [self, newpos]
753
++pos
754
var rslt = kwarg_key.exec(s.substring(newpos))
Mar 19, 2018
755
if(! rslt){
756
throw _b_.ValueError.$factory("incomplete format key")
757
}
758
var key = rslt[1]
759
newpos += rslt[0].length
Mar 23, 2018
760
try{
761
var self = getitem(key)
Mar 19, 2018
762
}catch(err){
763
if(err.__class__ === _b_.KeyError){
764
throw err
765
}
766
throw _b_.TypeError.$factory("format requires a mapping")
768
return get_string_value(s, self)
769
}
770
771
var $get_arg_string = function(s) {
772
// returns [self, newpos]
773
var self
775
// non-tuple args
Mar 19, 2018
776
if(argpos === null){
777
// args is the value
Mar 19, 2018
779
}else{
780
self = args[argpos++]
Mar 19, 2018
781
if(self === undefined){
782
throw _b_.TypeError.$factory(
783
"not enough arguments for format string")
Sep 5, 2014
784
}
785
}
786
return get_string_value(s, self)
788
var get_string_value = function(s, self) {
789
// todo: get flags, type
790
// todo: string value based on flags, type, value
Mar 19, 2018
791
var flags = {"pad_char": " "}
792
do{
793
var func = char_mapping[s[newpos]]
Mar 23, 2018
794
try{
Mar 19, 2018
795
if(func === undefined){
796
throw new UnsupportedChar()
Mar 19, 2018
797
}else{
798
var ret = func(self, flags)
Mar 19, 2018
799
if(ret !== undefined){
800
return ret
801
}
802
++newpos
803
}
Mar 19, 2018
804
}catch (err){
805
if(err.name == "UnsupportedChar"){
806
invalid_char = s[newpos]
Mar 19, 2018
807
if(invalid_char === undefined){
808
throw _b_.ValueError.$factory("incomplete format")
Mar 19, 2018
810
throw _b_.ValueError.$factory(
811
"unsupported format character '" + invalid_char +
812
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
813
") at index " + newpos)
814
}else if(err.name === "NotANumber"){
815
var try_char = s[newpos],
816
cls = self.__class__
817
if(!cls){
818
if(typeof(self) === "string"){
819
cls = "str"
820
}else{
821
cls = typeof(self)
Mar 19, 2018
823
}else{
Mar 19, 2018
826
throw _b_.TypeError.$factory("%" + try_char +
827
" format: a number is required, not " + cls)
828
}else{
829
throw err
830
}
Sep 5, 2014
831
}
Mar 19, 2018
832
}while (true)
Sep 5, 2014
833
}
834
var nbph = 0 // number of placeholders
Mar 19, 2018
835
do{
836
var newpos = self.indexOf("%", pos)
837
if(newpos < 0){
838
ret += self.substring(pos)
839
break
840
}
841
ret += self.substring(pos, newpos)
842
++newpos
Mar 19, 2018
843
if(newpos < length){
844
if(self[newpos] === "%"){
845
ret += "%"
846
}else{
Mar 19, 2018
848
if(self[newpos] === "("){
849
++newpos
850
ret += $get_kwarg_string(self)
Mar 23, 2018
851
}else{
852
ret += $get_arg_string(self)
853
}
854
}
Mar 19, 2018
855
}else{
856
// % at end of string
857
throw _b_.ValueError.$factory("incomplete format")
858
}
859
pos = newpos + 1
Mar 19, 2018
860
}while(pos < length)
861
862
if(argpos !== null){
863
if(args.length > argpos){
864
throw _b_.TypeError.$factory(
865
"not enough arguments for format string")
866
}else if(args.length < argpos){
867
throw _b_.TypeError.$factory(
868
"not all arguments converted during string formatting")
Mar 19, 2018
870
}else if(nbph == 0){
871
throw _b_.TypeError.$factory(
872
"not all arguments converted during string formatting")
Sep 5, 2014
876
Sep 5, 2014
878
str
Feb 10, 2018
879
str.__mul__ = function(){
Mar 19, 2018
880
var $ = $B.args("__mul__", 2, {self: null, other: null},
881
["self", "other"], arguments, {}, null, null)
882
if(! _b_.isinstance($.other, _b_.int)){throw _b_.TypeError.$factory(
Mar 19, 2018
883
"Can't multiply sequence by non-int of type '" +
885
return $.self.valueOf().repeat($.other)
Sep 5, 2014
886
}
887
888
str.__ne__ = function(self, other){
889
return other !== self.valueOf()
890
}
Sep 5, 2014
891
892
function __newobj__(){
893
// __newobj__ is called with a generator as only argument
894
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
895
args = $.args
896
var res = args[1]
897
res.__class__ = args[0]
898
return res
899
}
900
901
str.__reduce_ex__ = function(self){
902
return $B.fast_tuple([
903
__newobj__,
904
$B.fast_tuple([self.__class__ || _b_.str, self]),
905
_b_.None,
906
_b_.None])
907
}
908
str
Feb 10, 2018
909
str.__repr__ = function(self){
911
var t = {
912
8: "\\x08",
913
9: "\\t",
914
10: "\\n",
915
11: "\\x0b",
916
12: "\\x0c",
917
13: "\\r",
918
92: "\\\\"
919
}
920
var repl = '',
921
chars = to_chars(self)
922
for(var i = 0; i < chars.length; i++){
923
var cp = _b_.ord(chars[i])
924
if(t[cp] !== undefined){
925
repl += t[cp]
926
}else if($B.is_unicode_cn(cp)){
927
var s = cp.toString(16)
928
while(s.length < 4){
929
s = '0' + s
930
}
931
repl += '\\u' + s
932
}else if(cp < 0x20 || (cp >= 0x7f && cp < 0xa0)){
933
cp = cp.toString(16)
934
if(cp.length < 2){
935
cp = '0' + cp
936
}
937
repl += '\\x' + cp
938
}else if(cp >= 0x300 && cp <= 0x36F){
939
repl += "\u200B" + chars[i]
Mar 19, 2018
945
if(res.search('"') == -1 && res.search("'") == -1){
946
return "'" + res + "'"
947
}else if(self.search('"') == -1){
948
return '"' + res + '"'
949
}
950
var qesc = new RegExp("'", "g") // to escape single quote
951
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
952
return res
953
}
954
955
str.__setattr__ = function(self, attr, value){
956
if(typeof self === "string"){
957
if(str.hasOwnProperty(attr)){
958
throw _b_.AttributeError.$factory("'str' object attribute '" +
959
attr + "' is read-only")
960
}else{
961
throw _b_.AttributeError.$factory(
962
"'str' object has no attribute '" + attr + "'")
963
}
964
}
965
// str subclass : use __dict__
966
_b_.dict.$setitem(self.__dict__, attr, value)
967
return $N
968
}
969
Mar 19, 2018
970
str.__setitem__ = function(self, attr, value){
971
throw _b_.TypeError.$factory(
972
"'str' object does not support item assignment")
Sep 5, 2014
973
}
Mar 27, 2019
975
var combining = []
976
for(var cp = 0x300; cp <= 0x36F; cp++){
977
combining.push(String.fromCharCode(cp))
978
}
979
var combining_re = new RegExp("(" + combining.join("|") + ")", "g")
str
Feb 10, 2018
981
str.__str__ = function(self){
982
var repl = '',
983
chars = to_chars(self)
984
if(chars.length == self.length){
985
return self.replace(combining_re, "\u200B$1")
986
}
987
for(var i = 0; i < chars.length; i++){
988
var cp = _b_.ord(chars[i])
989
if(cp >= 0x300 && cp <= 0x36F){
990
repl += "\u200B" + chars[i]
991
}else{
992
repl += chars[i]
993
}
994
}
995
return repl
Sep 5, 2014
996
}
Mar 19, 2018
998
str.toString = function(){return "string!"}
Sep 5, 2014
999
1000
// generate comparison methods
1001
var $comp_func = function(self,other){
1002
if(typeof other !== "string"){return _b_.NotImplemented}
Sep 5, 2014
1003
return self > other
1004
}
Mar 19, 2018
1005
$comp_func += "" // source code
1006
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
1007
for(var $op in $comps){
Mar 19, 2018
1008
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
1009
}
1010
1011
// add "reflected" methods
str
Feb 10, 2018
1012
$B.make_rmethods(str)
Sep 5, 2014
1013
1014
// unsupported operations
Mar 19, 2018
1015
var $notimplemented = function(self, other){
1016
throw _b_.NotImplementedError.$factory(
Mar 19, 2018
1017
"OPERATOR not implemented for class str")
Sep 5, 2014
1018
}
1019
1020
str.capitalize = function(self){
1021
var $ = $B.args("capitalize", 1, {self}, ["self"],
1022
arguments, {}, null, null)
1023
if(self.length == 0){
1024
return ""
1025
}
1026
return self.charAt(0).toUpperCase() + self.substr(1)
1027
}
1028
1029
str.casefold = function(self){
1030
var $ = $B.args("casefold", 1, {self}, ["self"],
1031
arguments, {}, null, null),
1032
res = "",
1033
char,
1034
cf,
1035
chars = to_chars($.self)
1036
1037
for(var i = 0, len = chars.length; i < len; i++){
1038
char = chars[i]
1039
cf = $B.unicode_casefold[char]
1040
if(cf){
1041
cf.forEach(function(cp){
1042
res += String.fromCharCode(cp)
1043
})
1044
}else{
1046
}
1047
}
1048
return res
1049
}
Sep 5, 2014
1050
Mar 19, 2018
1051
str.center = function(){
1052
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
1053
["self", "width", "fillchar"],
1054
arguments, {fillchar:" "}, null, null),
1055
self = $.self
Mar 19, 2018
1057
if($.width <= self.length) {return self}
Mar 19, 2018
1059
var pad = parseInt(($.width - self.length) / 2),
1060
res = $.fillchar.repeat(pad)
Sep 5, 2014
1061
res += self + res
1062
if(res.length < $.width){
1063
res += $.fillchar
1064
}
Sep 5, 2014
1065
return res
1066
}
1067
str
Feb 10, 2018
1068
str.count = function(){
Mar 19, 2018
1069
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
1070
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
1072
if(!(typeof $.sub == "string")){
1073
throw _b_.TypeError.$factory("Can't convert '" + $B.class_name($.sub) +
1074
"' object to str implicitly")
1075
}
Mar 19, 2018
1077
if($.start !== null){
1079
if($.stop !== null){
1080
_slice = _b_.slice.$factory($.start, $.stop)
1081
}else{
1082
_slice = _b_.slice.$factory($.start, $.self.length)
1083
}
str
Feb 10, 2018
1084
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
1086
if($.self.length + $.sub.length == 0){
1087
return 1
1088
}
Mar 19, 2018
1090
if($.sub.length == 0){
1091
if($.start == $.self.length){
1092
return 1
1093
}else if(substr.length == 0){
1094
return 0
1095
}
Mar 19, 2018
1096
return substr.length + 1
Mar 19, 2018
1098
var n = 0,
1099
pos = 0
1100
while(pos < substr.length){
1101
pos = substr.indexOf($.sub, pos)
1102
if(pos >= 0){
1103
n++
1104
pos += $.sub.length
1105
}else{
1106
break
1107
}
Sep 5, 2014
1108
}
1109
return n
1110
}
1111
1112
str.encode = function(){
1113
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
1114
["self", "encoding", "errors"], arguments,
1115
{encoding: "utf-8", errors: "strict"}, null, null)
1116
if($.encoding == "rot13" || $.encoding == "rot_13"){
1117
// Special case : returns a string
Mar 19, 2018
1118
var res = ""
1119
for(var i = 0, len = $.self.length; i < len ; i++){
1120
var char = $.self.charAt(i)
Mar 19, 2018
1121
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
1122
res += String.fromCharCode(String.charCodeAt(char) + 13)
1123
}else if(("m" < char && char <= "z") ||
1124
("M" < char && char <= "Z")){
1125
res += String.fromCharCode(String.charCodeAt(char) - 13)
1126
}else{res += char}
1127
}
1128
return res
1129
}
1130
return _b_.bytes.__new__(_b_.bytes, $.self, $.encoding, $.errors)
Sep 5, 2014
1131
}
1132
str
Feb 10, 2018
1133
str.endswith = function(){
1134
// Return True if the string ends with the specified suffix, otherwise
1135
// return False. suffix can also be a tuple of suffixes to look for.
1136
// With optional start, test beginning at that position. With optional
Sep 5, 2014
1137
// end, stop comparing at that position.
Mar 19, 2018
1138
var $ = $B.args("endswith", 4,
1139
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
1140
["self", "suffix", "start", "end"],
1141
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
1142
1143
normalize_start_end($)
1144
1145
var suffixes = $.suffix
1146
if(! _b_.isinstance(suffixes,_b_.tuple)){
1147
suffixes = [suffixes]
1148
}
1150
var chars = to_chars($.self),
1151
s = chars.slice($.start, $.end)
Mar 19, 2018
1152
for(var i = 0, len = suffixes.length; i < len; i++){
1153
var suffix = suffixes[i]
1154
if(! _b_.isinstance(suffix, str)){
1155
throw _b_.TypeError.$factory(
1156
"endswith first arg must be str or a tuple of str, not int")
1157
}
Mar 19, 2018
1158
if(suffix.length <= s.length &&
1159
s.slice(s.length - suffix.length).join('') == suffix){
1160
return true
1161
}
Sep 5, 2014
1162
}
1163
return false
1164
}
1165
str
Feb 10, 2018
1166
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
1167
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
1168
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
1169
var s = $B.$GetInt($.tabsize),
1170
col = 0,
1171
pos = 0,
1172
res = "",
1173
chars = to_chars(self)
1174
if(s == 1){
1175
return self.replace(/\t/g," ")
1176
}
1177
while(pos < chars.length){
1178
var car = chars[pos]
Mar 19, 2018
1180
case "\t":
1181
while(col % s > 0){
1182
res += " ";
1183
col++
1184
}
Mar 19, 2018
1186
case "\r":
1187
case "\n":
1188
res += car
1189
col = 0
1190
break
1191
default:
1192
res += car
1193
col++
1194
break
1195
}
1196
pos++
1197
}
1198
return res
Sep 5, 2014
1199
}
1200
str
Feb 10, 2018
1201
str.find = function(){
1202
// Return the lowest index in the string where substring sub is found,
1203
// such that sub is contained in the slice s[start:end]. Optional
1204
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
1205
// Return -1 if sub is not found.
Mar 19, 2018
1206
var $ = $B.args("str.find", 4,
1207
{self: null, sub: null, start: null, end: null},
1208
["self", "sub", "start", "end"],
1209
arguments, {start: 0, end: null}, null, null)
1210
check_str($.sub)
1213
if(!_b_.isinstance($.start, _b_.int) ||
1214
!_b_.isinstance($.end, _b_.int)){
Mar 19, 2018
1215
throw _b_.TypeError.$factory("slice indices must be " +
1216
"integers or None or have an __index__ method")}
1217
// Can't use string.substring(start, end) because if end < start,
1218
// Javascript transforms it into substring(end, start)...
1219
var s = ""
1220
for(var i = $.start; i < $.end; i++){
1221
s += $.self.charAt(i)
1222
}
1224
var len = str.__len__($.self)
1225
1226
if($.sub.length == 0 && $.start == len){
1227
return len
1228
}
1229
if(s.length + $.sub.length == 0){
1230
return -1
1231
}
Mar 19, 2018
1233
var last_search = s.length - $.sub.length
1234
for(var i = 0; i <= last_search; i++){
1235
if(s.substr(i, $.sub.length) == $.sub){
1236
return $.start + str.__len__(s.substr(0, i))
1237
}
Sep 5, 2014
1238
}
Sep 5, 2014
1240
}
1241
1242
// Next function used by method .format()
1243
1244
$B.parse_format = function(fmt_string){
Sep 5, 2014
1245
1246
// Parse a "format string", as described in the Python documentation
1247
// Return a format object. For the format string
1248
// a.x[z]!r:...
1249
// the object has attributes :
1250
// - name : "a"
1251
// - name_ext : [".x", "[z]"]
1252
// - conv : r
1253
// - spec : rest of string after :
Sep 5, 2014
1254
Mar 19, 2018
1255
var elts = fmt_string.split(":"),
1256
name,
1257
conv,
1258
spec,
Mar 19, 2018
1259
name_ext = []
Mar 19, 2018
1260
if(elts.length == 1){
1261
// No : in the string : it only contains a name
1262
name = fmt_string
1263
}else{
1264
// name is before the first ":"
1265
// spec (the format specification) is after
1266
name = elts[0]
Mar 19, 2018
1267
spec = elts.splice(1).join(":")
Mar 19, 2018
1270
var elts = name.split("!")
1271
if(elts.length > 1){
1272
name = elts[0]
1273
conv = elts[1] // conversion flag
Sep 5, 2014
1275
Mar 19, 2018
1276
if(name !== undefined){
1277
// "name' may be a subscription or attribute
1278
// Put these "extensions" in the list "name_ext"
1279
function name_repl(match){
1280
name_ext.push(match)
Mar 19, 2018
1281
return ""
1282
}
1283
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1284
name = name.replace(name_ext_re, name_repl)
1285
}
Sep 5, 2014
1286
1287
return {name: name, name_ext: name_ext,
1288
conv: conv, spec: spec || "", string: fmt_string}
Sep 5, 2014
1290
1291
$B.split_format = function(self){
1292
// Parse self to detect formatting instructions
1293
// Create a list "parts" made of sections of the string :
1294
// - elements of even rank are literal text
1295
// - elements of odd rank are "format objects", built from the
1296
// format strings in self (of the form {...})
Mar 19, 2018
1297
var pos = 0,
1298
_len = self.length,
Mar 19, 2018
1300
text = "",
1301
parts = [],
1302
rank = 0
1303
while(pos < _len){
1304
car = self.charAt(pos)
Mar 21, 2018
1305
if(car == "{" && self.charAt(pos + 1) == "{"){
1306
// replace {{ by literal {
Mar 19, 2018
1307
text += "{"
1308
pos += 2
1309
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1310
// replace }} by literal }
Mar 19, 2018
1311
text += "}"
1312
pos += 2
1313
}else if(car == "{"){
1314
// Start of a format string
1316
// Store current literal text
1317
parts.push(text)
1318
1319
// Search the end of the format string, ie the } closing the
1320
// opening {. Since the string can contain other pairs {} for
1321
// nested formatting, an integer nb is incremented for each { and
1322
// decremented for each } ; the end of the format string is
Mar 19, 2018
1323
// reached when nb == 0
1324
var end = pos + 1,
1325
nb = 1
1326
while(end < _len){
1327
if(self.charAt(end) == "{"){nb++; end++}
1328
else if(self.charAt(end) == "}"){
1329
nb--; end++
1330
if(nb == 0){
1331
// End of format string
Mar 19, 2018
1332
var fmt_string = self.substring(pos + 1, end - 1)
1333
1334
// Create a format object, by function parse_format
1335
var fmt_obj = $B.parse_format(fmt_string)
1336
fmt_obj.raw_name = fmt_obj.name
1337
fmt_obj.raw_spec = fmt_obj.spec
1338
1339
// If no name is explicitely provided, use the rank
1340
if(!fmt_obj.name){
Mar 19, 2018
1341
fmt_obj.name = rank + ""
Sep 5, 2014
1344
Mar 19, 2018
1345
if(fmt_obj.spec !== undefined){
1346
// "spec" may contain "nested replacement fields"
1347
// Replace empty fields by the rank in positional
1348
// arguments
1349
function replace_nested(name, key){
1350
if(key == ""){
1351
// Use implicit rank
1352
return "{" + rank++ + "}"
1356
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
1357
replace_nested)
1358
}
1360
// Store format object in list "parts"
1361
parts.push(fmt_obj)
Mar 19, 2018
1362
text = ""
1363
break
1364
}
1365
}else{end++}
Sep 5, 2014
1366
}
1367
if(nb > 0){
1368
throw _b_.ValueError.$factory("wrong format " + self)
1369
}
1371
}else{
1372
text += car
1373
pos++
1374
}
1375
}
1376
if(text){
1377
parts.push(text)
Sep 5, 2014
1378
}
1379
return parts
1380
}
1381
1382
str.format = function(self) {
1383
// Special management of keyword arguments if str.format is called by
1384
// str.format_map(mapping) : the argument "mapping" might not be a
1385
// dictionary
1386
var last_arg = $B.last(arguments)
1387
if(last_arg.$nat == "mapping"){
1388
var mapping = last_arg.mapping,
1389
getitem = $B.$getattr(mapping, "__getitem__")
1390
// Get the rest of the arguments
1391
var args = []
1392
for(var i = 0, len = arguments.length - 1; i < len; i++){
1393
args.push(arguments[i])
1394
}
1395
var $ = $B.args("format", 1, {self: null}, ["self"],
1396
args, {}, "$args", null)
1397
}else{
1398
var $ = $B.args("format", 1, {self: null}, ["self"],
1399
arguments, {}, "$args", "$kw"),
1400
mapping = $.$kw, // dictionary
1401
getitem = function(key){
1402
return _b_.dict.$getitem(mapping, key)
1403
}
1404
}
1405
var parts = $B.split_format($.self)
1406
1407
// Apply formatting to the values passed to format()
Mar 19, 2018
1408
var res = "",
1409
fmt
Mar 19, 2018
1411
for(var i = 0; i < parts.length; i++){
1412
// Literal text is added unchanged
Mar 19, 2018
1413
if(typeof parts[i] == "string"){res += parts[i]; continue}
1415
// Format objects
1416
fmt = parts[i]
1417
1418
if(fmt.spec !== undefined){
1419
// "spec" may contain "nested replacement fields"
1420
// In this case, evaluate them using the positional
1421
// or keyword arguments passed to format()
1422
function replace_nested(name, key){
1423
if(/\d+/.exec(key)){
1424
// If key is numeric, search in positional
1425
// arguments
1426
return _b_.tuple.__getitem__($.$args,
1427
parseInt(key))
1428
}else{
1429
// Else try in keyword arguments
1430
return _b_.dict.__getitem__($.$kw, key)
1431
}
1432
}
1433
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1434
replace_nested)
1435
}
Mar 21, 2018
1436
if(fmt.name.charAt(0).search(/\d/) > -1){
1437
// Numerical reference : use positional arguments
1438
var pos = parseInt(fmt.name),
Feb 11, 2018
1439
value = _b_.tuple.__getitem__($.$args, pos)
1440
}else{
1441
// Use keyword arguments
1442
var value = getitem(fmt.name)
1443
}
1444
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1445
for(var j = 0; j < fmt.name_ext.length; j++){
1446
var ext = fmt.name_ext[j]
Mar 19, 2018
1447
if(ext.charAt(0) == "."){
1449
value = $B.$getattr(value, ext.substr(1))
1450
}else{
1451
// Subscription
Mar 19, 2018
1452
var key = ext.substr(1, ext.length - 2)
1453
// An index made of digits is transformed into an integer
Mar 19, 2018
1454
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1455
value = $B.$getattr(value, "__getitem__")(key)
Feb 12, 2018
1458
1459
// If the conversion flag is set, first call a function to convert
1460
// the value
Mar 19, 2018
1461
if(fmt.conv == "a"){value = _b_.ascii(value)}
1462
else if(fmt.conv == "r"){value = _b_.repr(value)}
1463
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1465
// Call attribute __format__ to perform the actual formatting
1466
if(value.$is_class || value.$factory){
1467
// For classes, don't use the class __format__ method
1468
res += value.__class__.__format__(value, fmt.spec)
1470
res += $B.$getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1472
}
Sep 5, 2014
1474
}
1475
1476
str.format_map = function(self, mapping){
1477
var $ = $B.args("format_map", 2, {self: null, mapping: null},
1478
['self', 'mapping'], arguments, {}, null, null)
1479
return str.format(self, {$nat: 'mapping', mapping})
Sep 5, 2014
1480
}
1481
str
Feb 10, 2018
1482
str.index = function(self){
Sep 5, 2014
1483
// Like find(), but raise ValueError when the substring is not found.
1484
var res = str.find.apply(null, arguments)
1485
if(res === -1){
1486
throw _b_.ValueError.$factory("substring not found")
1487
}
Sep 5, 2014
1488
return res
1489
}
1490
1491
str.isascii = function(self){
1492
/* Return true if the string is empty or all characters in the string are
1493
ASCII, false otherwise. ASCII characters have code points in the range
1494
U+0000-U+007F. */
1495
for(var i = 0, len = self.length; i < len; i++){
1496
if(self.charCodeAt(i) > 127){
1497
return false
1498
}
1499
}
1500
return true
1501
}
1502
1503
str.isalnum = function(self){
1504
/* Return true if all characters in the string are alphanumeric and there
1505
is at least one character, false otherwise. A character c is alphanumeric
1506
if one of the following returns True: c.isalpha(), c.isdecimal(),
1507
c.isdigit(), or c.isnumeric(). */
1508
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1509
arguments, {}, null, null),
1510
cp
1511
for(var char of to_chars(self)){
1512
cp = _b_.ord(char)
1513
if(unicode_tables.Ll[cp] ||
1514
unicode_tables.Lu[cp] ||
1515
unicode_tables.Lm[cp] ||
1516
unicode_tables.Lt[cp] ||
1517
unicode_tables.Lo[cp] ||
1518
unicode_tables.Nd[cp] ||
1519
unicode_tables.digits[cp] ||
1520
unicode_tables.numeric[cp]){
1521
continue
1522
}
1523
return false
1524
}
1525
return true
1526
}
1527
1528
str.isalpha = function(self){
1529
/* Return true if all characters in the string are alphabetic and there is
1530
at least one character, false otherwise. Alphabetic characters are those
1531
characters defined in the Unicode character database as "Letter", i.e.,
1532
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1533
or "Lo". */
1534
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1535
arguments, {}, null, null),
1536
cp
1537
for(var char of to_chars(self)){
1538
cp = _b_.ord(char)
1539
if(unicode_tables.Ll[cp] ||
1540
unicode_tables.Lu[cp] ||
1541
unicode_tables.Lm[cp] ||
1542
unicode_tables.Lt[cp] ||
1543
unicode_tables.Lo[cp]){
1544
continue
1545
}
1546
return false
1547
}
1548
return true
1549
}
1550
1551
str.isdecimal = function(self){
1552
/* Return true if all characters in the string are decimal characters and
1553
there is at least one character, false otherwise. Decimal characters are
1554
those that can be used to form numbers in base 10, e.g. U+0660,
1555
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1556
the Unicode General Category "Nd". */
1557
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1558
arguments, {}, null, null),
1559
cp
1560
for(var char of to_chars(self)){
1561
cp = _b_.ord(char)
1562
if(! unicode_tables.Nd[cp]){
1563
return false
1564
}
1565
}
1566
return self.length > 0
1567
}
1568
1569
str.isdigit = function(self){
1570
/* Return true if all characters in the string are digits and there is at
1571
least one character, false otherwise. */
1572
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1573
arguments, {}, null, null),
1574
cp
1575
for(var char of to_chars(self)){
1576
cp = _b_.ord(char)
1577
if(! unicode_tables.digits[cp]){
1578
return false
1579
}
1580
}
1581
return self.length > 0
1582
}
1583
1584
str.isidentifier = function(self){
1585
/* Return true if the string is a valid identifier according to the
1586
language definition. */
1587
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1589
if(self.length == 0){
1590
return false
1591
}
1592
var chars = to_chars(self)
1593
if(unicode_tables.XID_Start[_b_.ord(chars[0])] === undefined){
1596
for(var char of chars){
1597
var cp = _b_.ord(char)
1598
if(unicode_tables.XID_Continue[cp] === undefined){
1599
return false
1600
}
1601
}
1602
}
1603
return true
1604
}
1605
1606
str.islower = function(self){
1607
/* Return true if all cased characters 4 in the string are lowercase and
1608
there is at least one cased character, false otherwise. */
1609
var $ = $B.args("islower", 1, {self: null}, ["self"],
1610
arguments, {}, null, null),
1611
has_cased = false,
1614
for(var char of to_chars(self)){
1615
cp = _b_.ord(char)
1616
if(unicode_tables.Ll[cp]){
1617
has_cased = true
1618
continue
1619
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
1620
return false
1621
}
1622
}
1623
return has_cased
1624
}
1625
1626
str.isnumeric = function(self){
1627
/* Return true if all characters in the string are numeric characters, and
1628
there is at least one character, false otherwise. Numeric characters
1629
include digit characters, and all characters that have the Unicode numeric
1630
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1631
characters are those with the property value Numeric_Type=Digit,
1632
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1633
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1634
arguments, {}, null, null)
1635
for(var char of to_chars(self)){
1636
if(! unicode_tables.numeric[_b_.ord(char)]){
1637
return false
1638
}
1639
}
1640
return self.length > 0
1641
}
1642
1643
var unprintable = {},
1644
unprintable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1645
1646
str.isprintable = function(self){
1647
/* Return true if all characters in the string are printable or the string
1648
is empty, false otherwise. Nonprintable characters are those characters
1649
defined in the Unicode character database as "Other" or "Separator",
1650
excepting the ASCII space (0x20) which is considered printable. */
1651
1652
// Set unprintable if not set yet
1653
if(Object.keys(unprintable).length == 0){
1654
for(var i = 0; i < unprintable_gc.length; i++){
1655
var table = unicode_tables[unprintable_gc[i]]
1657
unprintable[cp] = true
1660
unprintable[32] = true
1661
}
1662
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
1663
arguments, {}, null, null)
1664
for(var char of to_chars(self)){
1665
if(unprintable[_b_.ord(char)]){
1666
return false
1667
}
1668
}
1669
return true
1670
}
1671
1672
str.isspace = function(self){
1673
/* Return true if there are only whitespace characters in the string and
1674
there is at least one character, false otherwise.
1675
1676
A character is whitespace if in the Unicode character database, either its
1677
general category is Zs ("Separator, space"), or its bidirectional class is
1678
one of WS, B, or S.*/
1679
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1680
arguments, {}, null, null),
1681
cp
1682
for(var char of to_chars(self)){
1683
cp = _b_.ord(char)
1684
if(! unicode_tables.Zs[cp] &&
1685
$B.unicode_bidi_whitespace.indexOf(cp) == -1){
1686
return false
1687
}
1688
}
1689
return self.length > 0
1690
}
1691
1692
str.istitle = function(self){
1693
/* Return true if the string is a titlecased string and there is at least
1694
one character, for example uppercase characters may only follow uncased
1695
characters and lowercase characters only cased ones. Return false
1696
otherwise. */
1697
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1698
arguments, {}, null, null)
1699
return self.length > 0 && str.title(self) == self
1700
}
1701
1702
str.isupper = function(self){
1703
/* Return true if all cased characters 4 in the string are lowercase and
1704
there is at least one cased character, false otherwise. */
1705
var $ = $B.args("islower", 1, {self: null}, ["self"],
1706
arguments, {}, null, null),
1710
for(var char of to_chars(self)){
1711
cp = _b_.ord(char)
1712
if(unicode_tables.Lu[cp]){
1713
is_upper = true
1714
continue
1715
}else if(unicode_tables.Ll[cp] || unicode_tables.Lt[cp]){
str
Feb 10, 2018
1723
str.join = function(){
Mar 19, 2018
1724
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1725
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1727
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1728
res = [],
Sep 5, 2014
1730
while(1){
1731
try{
1732
var obj2 = _b_.next(iterable)
1733
if(! _b_.isinstance(obj2, str)){
1734
throw _b_.TypeError.$factory("sequence item " + count +
1735
": expected str instance, " + $B.class_name(obj2) +
1736
" found")
1737
}
1738
res.push(obj2)
Sep 5, 2014
1739
}catch(err){
1740
if(_b_.isinstance(err, _b_.StopIteration)){
1741
break
1742
}
Sep 5, 2014
1743
else{throw err}
1744
}
1745
}
1746
return res.join($.self)
Sep 5, 2014
1747
}
1748
str
Feb 10, 2018
1749
str.ljust = function(self) {
Mar 19, 2018
1750
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1751
["self", "width", "fillchar"],
1752
arguments, {fillchar: " "}, null, null),
1753
len = str.__len__(self)
1755
if($.width <= len){
1756
return self
1757
}
1758
return self + $.fillchar.repeat($.width - len)
Sep 5, 2014
1759
}
1760
1761
str.lower = function(self){
1762
var $ = $B.args("lower", 1, {self: null}, ["self"],
1763
arguments, {}, null, null)
1764
return self.toLowerCase()
1765
}
1766
1767
str.lstrip = function(self, x){
Mar 19, 2018
1768
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1769
arguments, {chars:_b_.None}, null, null)
1770
if($.chars === _b_.None){
1771
return $.self.trimLeft()
1772
}
1773
var chars = to_chars(self)
1774
for(var i = 0, len = chars.length; i < len; i++){
1775
if($.chars.indexOf(chars[i]) === -1){
1776
return chars.slice(i).join('')
Mar 19, 2018
1779
return ""
Sep 5, 2014
1780
}
1781
1782
// note, maketrans should be a static function.
str
Feb 10, 2018
1783
str.maketrans = function() {
Mar 19, 2018
1784
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1785
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1789
if($.y === null && $.z === null){
1790
// If there is only one argument, it must be a dictionary mapping
1791
// Unicode ordinals (integers) or characters (strings of length 1) to
1792
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1793
// keys will then be converted to ordinals.
Mar 19, 2018
1794
if(! _b_.isinstance($.x, _b_.dict)){
1795
throw _b_.TypeError.$factory(
1796
"maketrans only argument must be a dict")
Feb 11, 2018
1798
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1799
for(var i = 0, len = items.length; i < len; i++){
1800
var k = items[i][0],
1801
v = items[i][1]
1802
if(! _b_.isinstance(k, _b_.int)){
1803
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1804
k = _b_.ord(k)
1805
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1806
" is not int or 1-char string")}
1807
}
Mar 19, 2018
1808
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1809
throw _b_.TypeError.$factory("dictionary value " + v +
1810
" is not None, integer or string")
1811
}
1812
_b_.dict.$setitem(_t, k, v)
1813
}
1814
return _t
1815
}else{
1816
// If there are two arguments, they must be strings of equal length,
1817
// and in the resulting dictionary, each character in x will be mapped
1818
// to the character at the same position in y
Mar 19, 2018
1819
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1820
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1821
}else if($.x.length !== $.y.length){
1822
throw _b_.TypeError.$factory(
1823
"maketrans arguments must be strings or same length")
1824
}else{
1825
var toNone = {}
Mar 19, 2018
1826
if($.z !== null){
1827
// If there is a third argument, it must be a string, whose
1828
// characters will be mapped to None in the result
Mar 19, 2018
1829
if(! _b_.isinstance($.z, _b_.str)){
1830
throw _b_.TypeError.$factory(
1831
"maketrans third argument must be a string")
Mar 19, 2018
1833
for(var i = 0, len = $.z.length; i < len; i++){
1834
toNone[_b_.ord($.z.charAt(i))] = true
1835
}
Mar 19, 2018
1837
for(var i = 0, len = $.x.length; i < len; i++){
1838
var key = _b_.ord($.x.charAt(i)),
1840
_b_.dict.$setitem(_t, key, value)
1841
}
1842
for(var k in toNone){
1843
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1844
}
1845
return _t
1846
}
1847
}
Sep 5, 2014
1848
}
1849
1850
str.maketrans.$type = "staticmethod"
1851
str
Feb 10, 2018
1852
str.partition = function() {
Mar 19, 2018
1853
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1854
arguments, {}, null, null)
1855
if($.sep == ""){
1856
throw _b_.ValueError.$factory("empty separator")
1857
}
Mar 19, 2018
1858
check_str($.sep)
1859
var chars = to_chars($.self),
1860
i = $.self.indexOf($.sep)
1861
if(i == -1){
1862
return _b_.tuple.$factory([$.self, "", ""])
1863
}
1864
return _b_.tuple.$factory([chars.slice(0, i).join(''), $.sep,
1865
chars.slice(i + $.sep.length).join('')])
Mar 19, 2018
1866
}
1867
1868
str.removeprefix = function(){
1869
var $ = $B.args("removeprefix", 2, {self: null, prefix: null},
1870
["self", "prefix"], arguments, {}, null, null)
1871
if(!_b_.isinstance($.prefix, str)){
1872
throw _b_.ValueError.$factory("prefix should be str, not " +
1873
`'${$B.class_name($.prefix)}'`)
1874
}
1875
if(str.startswith($.self, $.prefix)){
1876
return $.self.substr($.prefix.length)
1877
}
1878
return $.self.substr(0)
1879
}
1880
1881
str.removesuffix = function(){
1882
var $ = $B.args("removesuffix", 2, {self: null, prefix: null},
1883
["self", "suffix"], arguments, {}, null, null)
1884
if(!_b_.isinstance($.suffix, str)){
1885
throw _b_.ValueError.$factory("suffix should be str, not " +
1886
`'${$B.class_name($.prefix)}'`)
1887
}
1888
if($.suffix.length > 0 && str.endswith($.self, $.suffix)){
1889
return $.self.substr(0, $.self.length - $.suffix.length)
1890
}
1891
return $.self.substr(0)
1892
}
1893
Mar 19, 2018
1894
function $re_escape(str){
1895
var specials = "[.*+?|()$^"
1896
for(var i = 0, len = specials.length; i < len; i++){
1897
var re = new RegExp("\\"+specials.charAt(i), "g")
1898
str = str.replace(re, "\\"+specials.charAt(i))
1899
}
1900
return str
Sep 5, 2014
1901
}
1902
str
Feb 10, 2018
1903
str.replace = function(self, old, _new, count) {
1904
// Replaces occurrences of 'old' by '_new'. Count references
1905
// the number of times to replace. In CPython, negative or undefined
1906
// values of count means replace all.
Mar 19, 2018
1907
var $ = $B.args("replace", 4,
1908
{self: null, old: null, $$new: null, count: null},
1909
["self", "old", "$$new", "count"],
1910
arguments, {count: -1}, null, null),
1911
count = $.count,
1912
self = $.self,
1913
old = $.old,
1914
_new = $.$$new
1915
// Validate type of old
1916
check_str(old, "replace() argument 1 ")
1917
check_str(_new, "replace() argument 2 ")
1918
// Validate instance type of 'count'
1919
if(! _b_.isinstance(count,[_b_.int, _b_.float])){
1920
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
1921
"' object cannot be interpreted as an integer")
1922
}else if(_b_.isinstance(count, _b_.float)){
Mar 19, 2018
1923
throw _b_.TypeError.$factory("integer argument expected, got float")
1924
}
1925
if(count == 0){
1926
return self
1927
}
1928
if(count.__class__ == $B.long_int){
1929
count = parseInt(count.value)
1930
}
Mar 19, 2018
1931
if(old == ""){
1932
if(_new == ""){
1933
return self
1934
}
1935
if(self == ""){
1936
return _new
1937
}
Mar 19, 2018
1938
var elts = self.split("")
1939
if(count > -1 && elts.length >= count){
1940
var rest = elts.slice(count).join("")
1941
return _new + elts.slice(0, count).join(_new) + rest
1942
}else{
1943
return _new + elts.join(_new) + _new
1944
}
Mar 19, 2018
1946
var elts = str.split(self, old, count)
Sep 5, 2014
1947
}
Mar 19, 2018
1949
var res = self,
1950
pos = -1
1951
if(old.length == 0){
Mar 19, 2018
1953
for(var i = 0; i < elts.length; i++){
1954
res += elts[i] + _new
Mar 19, 2018
1956
return res + rest
1959
if(count < 0){
1960
count = res.length
1961
}
Mar 19, 2018
1962
while(count > 0){
1963
pos = res.indexOf(old, pos)
1964
if(pos < 0){
1965
break
1966
}
Mar 19, 2018
1967
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1968
pos = pos + _new.length
1969
count--
Mar 19, 2018
1971
return res
Sep 5, 2014
1972
}
1973
1974
str.rfind = function(self, substr){
1975
// Return the highest index in the string where substring sub is found,
1976
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1977
// start and end are interpreted as in slice notation. Return -1 on failure.
1978
if(arguments.length == 2 && typeof substr == "string"){
1979
return self.lastIndexOf(substr)
1980
}
Mar 19, 2018
1981
var $ = $B.args("rfind", 4,
Mar 19, 2018
1982
{self: null, sub: null, start: null, end: null},
1983
["self", "sub", "start", "end"],
1984
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1985
1988
check_str($.sub)
Mar 19, 2018
1990
if($.sub.length == 0){
1991
if($.start > $.self.length){
1992
return -1
1993
}else{
1994
return str.__len__($.self)
1995
}
Mar 19, 2018
2000
for(var i = $.end - sublen; i >= $.start; i--){
2001
if($.self.substr(i, sublen) == $.sub){
2002
return str.__len__($.self.substr(0, i))
2003
}
Sep 5, 2014
2006
}
2007
str
Feb 10, 2018
2008
str.rindex = function(){
Sep 5, 2014
2009
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
2010
var res = str.rfind.apply(null, arguments)
2011
if(res == -1){
2012
throw _b_.ValueError.$factory("substring not found")
2013
}
Sep 5, 2014
2014
return res
2015
}
2016
str
Feb 10, 2018
2017
str.rjust = function(self) {
Mar 19, 2018
2018
var $ = $B.args("rjust",3,
2019
{self: null, width: null, fillchar: null},
2020
["self", "width", "fillchar"],
2021
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
2022
2023
if($.width <= self.length){
2024
return self
2025
}
Sep 5, 2014
2026
2027
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
2028
}
2029
str
Feb 10, 2018
2030
str.rpartition = function(self,sep) {
Mar 19, 2018
2031
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
2032
arguments, {}, null, null)
2033
check_str($.sep)
2034
var self = reverse($.self),
2035
sep = reverse($.sep)
Mar 19, 2018
2036
var items = str.partition(self, sep).reverse()
2037
for(var i = 0; i < items.length; i++){
2038
items[i] = items[i].split("").reverse().join("")
2039
}
2040
return items
Sep 5, 2014
2041
}
2042
str
Feb 10, 2018
2043
str.rsplit = function(self) {
Mar 19, 2018
2044
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
2045
["self", "sep", "maxsplit"], arguments,
2046
{sep: _b_.None, maxsplit: -1}, null, null),
2047
sep = $.sep
2048
2049
// Use split on the reverse of the string and of separator
2050
var rev_str = reverse($.self),
2051
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
2052
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
2054
// Reverse the list, then each string inside the list
2055
rev_res.reverse()
Mar 19, 2018
2056
for(var i = 0; i < rev_res.length; i++){
2057
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
2060
}
2061
Mar 19, 2018
2062
str.rstrip = function(self, x){
2063
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
Mar 19, 2018
2064
arguments, {chars: _b_.None}, null, null)
2065
if($.chars === _b_.None){
2066
return $.self.trimRight()
2067
}
2068
var chars = to_chars(self)
2069
for(var j = chars.length - 1; j >= 0; j--){
2070
if($.chars.indexOf(chars[j]) == -1){
2071
return chars.slice(0, j + 1).join('')
Mar 19, 2018
2074
return ""
Sep 5, 2014
2075
}
2076
str
Feb 10, 2018
2077
str.split = function(){
Mar 19, 2018
2078
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
2079
["self", "sep", "maxsplit"], arguments,
2080
{sep: _b_.None, maxsplit: -1}, null, null),
2081
sep = $.sep,
2082
maxsplit = $.maxsplit,
2083
self = $.self,
2084
pos = 0
2085
if(maxsplit.__class__ === $B.long_int){
2086
maxsplit = parseInt(maxsplit.value)
2087
}
2088
if(sep == ""){
2089
throw _b_.ValueError.$factory("empty separator")
2090
}
Mar 19, 2018
2091
if(sep === _b_.None){
Sep 5, 2014
2092
var res = []
2093
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){
2094
pos++
2095
}
2096
if(pos === self.length - 1){
2097
return [self]
2098
}
Mar 19, 2018
2099
var name = ""
Sep 5, 2014
2100
while(1){
Mar 19, 2018
2101
if(self.charAt(pos).search(/\s/) == -1){
2102
if(name == ""){
2103
name = self.charAt(pos)
2104
}else{
2105
name += self.charAt(pos)
2106
}
Sep 5, 2014
2107
}else{
Mar 19, 2018
2108
if(name !== ""){
Sep 5, 2014
2109
res.push(name)
Mar 19, 2018
2110
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
2111
res.pop()
Mar 19, 2018
2112
res.push(name + self.substr(pos))
Sep 5, 2014
2113
return res
2114
}
Mar 19, 2018
2115
name = ""
Sep 5, 2014
2116
}
2117
}
2118
pos++
Mar 19, 2018
2119
if(pos > self.length - 1){
2120
if(name){
2121
res.push(name)
2122
}
Sep 5, 2014
2123
break
2124
}
2125
}
2126
return res
2127
}else{
Mar 19, 2018
2128
var res = [],
2129
s = "",
2130
seplen = sep.length
2131
if(maxsplit == 0){return [self]}
2132
while(pos < self.length){
2133
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
2136
if(maxsplit > -1 && res.length >= maxsplit){
2137
res.push(self.substr(pos))
2138
return res
2139
}
Mar 19, 2018
2140
s = ""
2141
}else{
2142
s += self.charAt(pos)
2143
pos++
Sep 5, 2014
2144
}
2145
}
Sep 5, 2014
2148
}
2149
}
2150
2151
str.splitlines = function(self) {
2152
var $ = $B.args('splitlines', 2, {self: null, keepends: null},
2153
['self','keepends'], arguments, {keepends: false},
2154
null, null)
2155
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
2156
throw _b_.TypeError('integer argument expected, got '+
2157
$B.get_class($.keepends).__name)
2158
}
2159
var keepends = _b_.int.$factory($.keepends),
2160
res = [],
2161
self = $.self,
2162
start = 0,
2163
pos = 0
2164
if(!self.length){
2165
return res
2166
}
2168
if(self.substr(pos, 2) == '\r\n'){
2169
res.push(self.slice(start, keepends ? pos + 2 : pos))
2170
start = pos = pos+2
2171
}else if(self[pos] == '\r' || self[pos] == '\n'){
2172
res.push(self.slice(start, keepends ? pos+1 : pos))
2173
start = pos = pos+1
2174
}else{
2175
pos++
2176
}
2177
}
2178
if(start < self.length){
2179
res.push(self.slice(start))
2180
}
2181
return res
2182
}
Sep 5, 2014
2183
str
Feb 10, 2018
2184
str.startswith = function(){
2185
// Return True if string starts with the prefix, otherwise return False.
2186
// prefix can also be a tuple of prefixes to look for. With optional
2187
// start, test string beginning at that position. With optional end,
Sep 5, 2014
2188
// stop comparing string at that position.
Mar 19, 2018
2189
var $ = $B.args("startswith", 4,
2190
{self: null, prefix: null, start: null, end: null},
2191
["self", "prefix", "start", "end"],
2192
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
2193
2194
normalize_start_end($)
2195
2196
var prefixes = $.prefix
2197
if(! _b_.isinstance(prefixes, _b_.tuple)){
2198
prefixes = [prefixes]
2199
}
2201
var s = to_chars($.self).slice($.start, $.end).join('')
Mar 19, 2018
2202
for(var i = 0, len = prefixes.length; i < len; i++){
2203
var prefix = prefixes[i]
2204
if(! _b_.isinstance(prefix, str)){
2205
throw _b_.TypeError.$factory("endswith first arg must be str " +
2206
"or a tuple of str, not int")
2207
}
2208
if(s.substr(0, prefix.length) == prefix){
2209
return true
2210
}
Sep 5, 2014
2211
}
2212
return false
2213
}
2214
str
Feb 10, 2018
2215
str.strip = function(){
Mar 19, 2018
2216
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
2217
arguments, {chars: _b_.None}, null, null)
2218
if($.chars === _b_.None){
2219
return $.self.trim()
2220
}
2221
var chars = to_chars($.self)
2222
for(var i = 0; i < chars.length; i++){
2223
if($.chars.indexOf(chars[i]) == -1){
Mar 19, 2018
2224
break
2227
for(var j = chars.length - 1; j >= i; j--){
2228
if($.chars.indexOf(chars[j]) == -1){
Mar 19, 2018
2229
break
2232
return chars.slice(i, j + 1).join('')
Sep 5, 2014
2233
}
2234
2235
str.swapcase = function(self){
2236
var $ = $B.args("swapcase", 1, {self}, ["self"],
2237
arguments, {}, null, null),
2238
res = "",
2239
cp
2240
2241
for(var char of to_chars(self)){
2242
cp = _b_.ord(char)
2243
if(unicode_tables.Ll[cp]){
2244
res += char.toUpperCase()
2245
}else if(unicode_tables.Lu[cp]){
2246
res += char.toLowerCase()
2249
}
2250
}
2251
return res
2252
}
2253
2254
str.title = function(self){
2255
var $ = $B.args("title", 1, {self}, ["self"],
2256
arguments, {}, null, null),
2257
state,
2260
for(var char of to_chars(self)){
2261
cp = _b_.ord(char)
2262
if(unicode_tables.Ll[cp]){
2269
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
2270
res += state ? char.toLowerCase() : char
2271
state = "word"
2272
}else{
2273
state = null
2275
}
2276
}
2277
return res
2278
}
2279
2280
str.translate = function(self, table){
Mar 19, 2018
2281
var res = [],
2282
getitem = $B.$getattr(table, "__getitem__"),
2283
cp
2284
for(var char of to_chars(self)){
2285
cp = _b_.ord(char)
2288
if(repl !== _b_.None){
2289
if(typeof repl == "string"){
2290
res.push(repl)
2291
}else if(typeof repl == "number"){
2292
res.push(String.fromCharCode(repl))
2293
}
2294
}
2295
}catch(err){
Sep 5, 2014
2298
}
Mar 19, 2018
2299
return res.join("")
Sep 5, 2014
2300
}
2301
2302
str.upper = function(self){
2303
var $ = $B.args("upper", 1, {self: null}, ["self"],
2304
arguments, {}, null, null)
2305
return self.toUpperCase()
2306
}
2307
Mar 19, 2018
2308
str.zfill = function(self, width){
Mar 19, 2018
2309
var $ = $B.args("zfill", 2, {self: null, width: null},
2310
["self", "width"], arguments, {}, null, null),
2311
len = str.__len__(self)
2312
if($.width <= len){
2313
return self
2314
}
Mar 19, 2018
2316
case "+":
2317
case "-":
2318
return self.charAt(0) +
2319
"0".repeat($.width - len) + self.substr(1)
2321
return "0".repeat($.width - len) + self
Sep 5, 2014
2323
}
2324
2325
str.$factory = function(arg, encoding, errors){
2326
if(arguments.length == 0){
2327
return ""
2328
}
2330
return $B.UndefinedClass.__str__()
2331
}else if(arg === null){
2332
return '<Javascript null>'
2334
if(encoding !== undefined){
2335
// Arguments may be passed as keywords (cf. issue #1060)
2336
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
2337
["arg", "encoding", "errors"], arguments,
2338
{encoding: "utf-8", errors: "strict"}, null, null),
2339
encoding = $.encoding,
2340
errors = $.errors
2341
}
2342
switch(typeof arg) {
Mar 19, 2018
2343
case "string":
Mar 27, 2019
2344
return str.__str__(arg)
Mar 19, 2018
2345
case "number":
2346
if(isFinite(arg)){return arg.toString()}
2349
if(arg.$is_class || arg.$factory){
2350
// arg is a class
2351
// In this case, str() doesn't use the attribute __str__ of the
2352
// class or its subclasses, but the attribute __str__ of the
2353
// class metaclass (usually "type") or its subclasses (usually
2354
// "object")
2355
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
2356
var func = $B.$getattr(arg.__class__, "__str__")
2358
}
2360
if(arg.__class__ && arg.__class__ === _b_.bytes &&
2361
encoding !== undefined){
2362
// str(bytes, encoding, errors) is equal to
2363
// bytes.decode(encoding, errors)
2364
return _b_.bytes.decode(arg, $.encoding, $.errors)
2366
// Implicit invocation of __str__ uses method __str__ on the class,
2367
// even if arg has an attribute __str__
2368
var klass = arg.__class__ || $B.get_class(arg)
2370
return $B.JSObj.__str__($B.JSObj.$factory(arg))
2372
var method = $B.$getattr(klass , "__str__", null)
2373
if(method === null ||
2374
// if not better than object.__str__, try __repr__
2375
(arg.__class__ && arg.__class__ !== _b_.object &&
2376
method.$infos && method.$infos.__func__ === _b_.object.__str__)){
2377
var method = $B.$getattr(klass, "__repr__")
Sep 5, 2014
2379
}
2380
catch(err){
2381
console.log("no __str__ for", arg)
Mar 19, 2018
2382
console.log("err ", err)
2383
if($B.debug > 1){console.log(err)}
2384
console.log("Warning - no method __str__ or __repr__, " +
2385
"default to toString", arg)
May 20, 2019
2386
throw err
Sep 5, 2014
2387
}
2388
return $B.$call(method)(arg)
Sep 5, 2014
2389
}
str
Feb 10, 2018
2390
2391
str.__new__ = function(cls){
Mar 19, 2018
2392
if(cls === undefined){
2393
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
2394
}
Mar 19, 2018
2395
return {__class__: cls}
Sep 5, 2014
2396
}
2397
str
Feb 10, 2018
2398
$B.set_func_names(str, "builtins")
Sep 5, 2014
2400
// dictionary and factory for subclasses of string
str
Feb 10, 2018
2401
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
2402
__class__: _b_.type,
2403
__mro__: [_b_.object],
2404
$infos: {
2405
__module__: "builtins",
2406
__name__: "str"
2407
},
str
Feb 10, 2018
2408
$is_class: true
Sep 5, 2014
2409
}
2410
str
Feb 10, 2018
2411
// the methods in subclass apply the methods in str to the
Sep 5, 2014
2412
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
2413
for(var $attr in str){
Mar 19, 2018
2414
if(typeof str[$attr] == "function"){
Mar 19, 2018
2415
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
2416
return function(){
Mar 19, 2018
2417
var args = [],
2418
pos = 0
2419
if(arguments.length > 0){
2420
var args = [arguments[0].valueOf()],
2421
pos = 1
2422
for(var i = 1, len = arguments.length; i < len; i++){
2423
args[pos++] = arguments[i]
Sep 5, 2014
2424
}
2425
}
Mar 19, 2018
2426
return str[attr].apply(null, args)
Sep 5, 2014
2427
}
2428
})($attr)
2429
}
2430
}
2431
str
Feb 10, 2018
2432
StringSubclass.__new__ = function(cls){
Sep 5, 2014
2435
str
Feb 10, 2018
2436
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
2438
_b_.str = str
2439
2440
// Function to parse the 2nd argument of format()
2441
$B.parse_format_spec = function(spec){
2442
if(spec == ""){
2443
this.empty = true
2444
}else{
Mar 19, 2018
2445
var pos = 0,
2446
aligns = "<>=^",
2447
digits = "0123456789",
2448
types = "bcdeEfFgGnosxX%",
2449
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
2450
if(align_pos != -1){
2451
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2452
// If the second char is also an alignment specifier, the
2453
// first char is the fill value
2454
this.fill = spec.charAt(0)
2455
this.align = spec.charAt(1)
2456
pos = 2
2457
}else{
2458
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
2459
this.align = aligns[align_pos]
2460
this.fill = " "
2461
pos++
2462
}
2463
}else{
2464
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
2465
if(spec.charAt(1) && align_pos != -1){
2466
// The second character defines alignment : fill is the first one
Mar 19, 2018
2467
this.align = aligns[align_pos]
2468
this.fill = spec.charAt(0)
2469
pos = 2
2470
}
2471
}
2472
var car = spec.charAt(pos)
Mar 19, 2018
2473
if(car == "+" || car == "-" || car == " "){
2474
this.sign = car
2475
pos++
2476
car = spec.charAt(pos)
2478
if(car == "#"){
2479
this.alternate = true; pos++; car = spec.charAt(pos)
2480
}
Mar 19, 2018
2481
if(car == "0"){
Mar 19, 2018
2482
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
2483
this.fill = "0"
2484
if(align_pos == -1){
2485
this.align = "="
2486
}
Mar 19, 2018
2487
pos++
2488
car = spec.charAt(pos)
2489
}
Mar 19, 2018
2490
while(car && digits.indexOf(car) > -1){
2491
if(this.width === undefined){
2492
this.width = car
2493
}else{
2494
this.width += car
2495
}
Mar 19, 2018
2496
pos++
2497
car = spec.charAt(pos)
2499
if(this.width !== undefined){
2500
this.width = parseInt(this.width)
2501
}
2502
if(this.width === undefined && car == "{"){
2503
// Width is determined by a parameter
2504
var end_param_pos = spec.substr(pos).search("}")
2505
this.width = spec.substring(pos, end_param_pos)
2506
console.log("width", "[" + this.width + "]")
2507
pos += end_param_pos + 1
2508
}
2509
if(car == ","){
2510
this.comma = true
2511
pos++
2512
car = spec.charAt(pos)
2513
}
Mar 19, 2018
2514
if(car == "."){
2515
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2516
throw _b_.ValueError.$factory(
2517
"Missing precision in format spec")
Mar 19, 2018
2519
this.precision = spec.charAt(pos + 1)
2520
pos += 2
2521
car = spec.charAt(pos)
2522
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
2523
this.precision += car
Mar 19, 2018
2524
pos++
2525
car = spec.charAt(pos)
2526
}
2527
this.precision = parseInt(this.precision)
2528
}
Mar 19, 2018
2529
if(car && types.indexOf(car) > -1){
2530
this.type = car
2531
pos++
2532
car = spec.charAt(pos)
2533
}
2534
if(pos !== spec.length){
2535
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
2539
this.toString = function(){
Mar 19, 2018
2540
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2541
(this.align || "") +
2542
(this.sign || "") +
2543
(this.alternate ? "#" : "") +
2544
(this.sign_aware ? "0" : "") +
2545
(this.width || "") +
2546
(this.comma ? "," : "") +
2547
(this.precision ? "." + this.precision : "") +
2548
(this.type || "")
2549
}
2550
}
2551
2552
$B.format_width = function(s, fmt){
Mar 19, 2018
2553
if(fmt.width && s.length < fmt.width){
2554
var fill = fmt.fill || " ",
2555
align = fmt.align || "<",
2556
missing = fmt.width - s.length
2557
switch(align){
Mar 19, 2018
2558
case "<":
2559
return s + fill.repeat(missing)
2560
case ">":
2561
return fill.repeat(missing) + s
2562
case "=":
2563
if("+-".indexOf(s.charAt(0)) > -1){
2564
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2565
}else{
Mar 19, 2018
2566
return fill.repeat(missing) + s
Mar 19, 2018
2568
case "^":
2569
var left = parseInt(missing / 2)
2570
return fill.repeat(left) + s + fill.repeat(missing - left)
2571
}
2572
}
2573
return s
2574
}
2575
2576
function fstring_expression(){
Mar 19, 2018
2577
this.type = "expression"
2578
this.expression = ""
2579
this.conversion = null
2580
this.fmt = null
2581
}
2582
2583
function fstring_error(msg, pos){
2584
error = Error(msg)
2585
error.position = pos
2586
throw error
2587
}
2588
2589
$B.parse_fstring = function(string){
2590
// Parse a f-string
2591
var elts = [],
2592
pos = 0,
Mar 19, 2018
2593
current = "",
2594
ctype = null,
2595
nb_braces = 0,
2596
car
2597
Mar 19, 2018
2598
while(pos < string.length){
2599
if(ctype === null){
2600
car = string.charAt(pos)
Mar 19, 2018
2601
if(car == "{"){
Mar 21, 2018
2602
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
2603
ctype = "string"
2604
current = "{"
2605
pos += 2
2606
}else{
Mar 19, 2018
2607
ctype = "expression"
2608
nb_braces = 1
2609
pos++
2610
}
Mar 19, 2018
2611
}else if(car == "}"){
Mar 21, 2018
2612
if(string.charAt(pos + 1) == car){
Mar 19, 2018
2613
ctype = "string"
2614
current = "}"
2615
pos += 2
2616
}else{
2617
fstring_error(" f-string: single '}' is not allowed",
2618
pos)
2619
}
2620
}else{
Mar 19, 2018
2621
ctype = "string"
2622
current = car
2623
pos++
Mar 19, 2018
2625
}else if(ctype == "string"){
2626
// end of string is the first single { or end of string
Mar 19, 2018
2627
var i = pos
2628
while(i < string.length){
2629
car = string.charAt(i)
Mar 19, 2018
2630
if(car == "{"){
Mar 21, 2018
2631
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
2632
current += "{"
2633
i += 2
2634
}else{
2635
elts.push(current)
Mar 19, 2018
2636
ctype = "expression"
2637
pos = i + 1
2638
break
2639
}
Mar 19, 2018
2640
}else if(car == "}"){
2641
if(string.charAt(i + 1) == car){
2642
current += car
2643
i += 2
2644
}else{
2645
fstring_error(" f-string: single '}' is not allowed",
2646
pos)
2647
}
2648
}else{
2649
current += car
2650
i++
2651
}
2652
}
Mar 19, 2018
2653
pos = i + 1
2654
}else if(ctype == "debug"){
2655
// after the equal sign, whitespace are ignored and the only
2656
// valid characters are } and :
2657
while(string.charAt(i) == " "){i++}
2658
if(string.charAt(i) == "}"){
2659
// end of debug expression
2660
elts.push(current)
2661
ctype = null
2662
current = ""
2663
pos = i + 1
2664
}
2665
}else{
2666
// End of expression is the } matching the opening {
2667
// There may be nested braces
2668
var i = pos,
2669
nb_braces = 1,
2670
nb_paren = 0,
2671
current = new fstring_expression()
Mar 19, 2018
2672
while(i < string.length){
2673
car = string.charAt(i)
Mar 19, 2018
2674
if(car == "{" && nb_paren == 0){
2675
nb_braces++
2676
current.expression += car
2677
i++
Mar 19, 2018
2678
}else if(car == "}" && nb_paren == 0){
2679
nb_braces -= 1
Mar 19, 2018
2680
if(nb_braces == 0){
2681
// end of expression
2682
if(current.expression == ""){
2683
fstring_error("f-string: empty expression not allowed",
2684
pos)
2685
}
2686
elts.push(current)
2687
ctype = null
Mar 19, 2018
2688
current = ""
2689
pos = i + 1
2692
current.expression += car
2693
i++
Mar 19, 2018
2694
}else if(car == "\\"){
2695
// backslash is not allowed in expressions
2696
throw Error("f-string expression part cannot include a" +
2697
" backslash")
Mar 19, 2018
2698
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
Mar 21, 2018
2699
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2700
if(current.expression.length == 0){
2701
throw Error("f-string: empty expression not allowed")
2702
}
Mar 19, 2018
2703
if("ars".indexOf(string.charAt(i + 1)) == -1){
2704
throw Error("f-string: invalid conversion character:" +
2705
" expected 's', 'r', or 'a'")
2706
}else{
Mar 19, 2018
2707
current.conversion = string.charAt(i + 1)
2708
i += 2
2709
}
Mar 19, 2018
2710
}else if(car == "("){
2711
nb_paren++
2712
current.expression += car
2713
i++
Mar 19, 2018
2714
}else if(car == ")"){
2715
nb_paren--
2716
current.expression += car
2717
i++
Mar 19, 2018
2718
}else if(car == '"'){
2719
// triple string ?
Mar 19, 2018
2720
if(string.substr(i, 3) == '"""'){
2721
var end = string.indexOf('"""', i + 3)
2722
if(end == -1){
2723
fstring_error("f-string: unterminated string", pos)
Mar 19, 2018
2724
}else{
2725
var trs = string.substring(i, end + 3)
2726
trs = trs.replace("\n", "\\n\\")
2727
current.expression += trs
Mar 19, 2018
2728
i = end + 3
2729
}
2730
}else{
Mar 19, 2018
2731
var end = string.indexOf('"', i + 1)
2732
if(end == -1){
2733
fstring_error("f-string: unterminated string", pos)
Mar 19, 2018
2734
}else{
2735
current.expression += string.substring(i, end + 1)
2736
i = end + 1
2737
}
2738
}
Mar 19, 2018
2739
}else if(nb_paren == 0 && car == ":"){
2740
current.fmt = true
2741
current.expression += car
2742
i++
2743
}else if(car == "="){
2744
// might be a "debug expression", eg f"{x=}"
2745
var ce = current.expression,
2746
last_char = ce.charAt(ce.length - 1),
2747
last_char_re = ('()'.indexOf(last_char) > -1 ? "\\" : "") + last_char
2751
string.charAt(i + 1) == "=" ||
2752
"=!<>:".search(last_char_re) > -1){
2753
current.expression += car //+ string.charAt(i + 1)
2754
i += 1
2755
}else{
2756
// add debug string
2757
tail = car
2758
while(string.charAt(i + 1).match(/\s/)){
2759
tail += string.charAt(i + 1)
2760
i++
2761
}
2762
elts.push(current.expression + tail)
2763
// remove trailing whitespace from expression
2764
while(ce.match(/\s$/)){
2765
ce = ce.substr(0, ce.length - 1)
2766
}
2767
current.expression = ce
2768
ctype = "debug"
2769
i++
2770
}
2771
}else{
2772
current.expression += car
2773
i++
2774
}
2775
}
Mar 21, 2018
2776
if(nb_braces > 0){
2777
fstring_error("f-string: expected '}'", pos)
2778
}
2779
}
2780
}
Mar 19, 2018
2781
if(current.length > 0){elts.push(current)}
2782
return elts
2783
}
2784
2785
var _chr = $B.codepoint2jsstring = function(i){
2786
if(i >= 0x10000 && i <= 0x10FFFF){
2787
var code = (i - 0x10000)
2788
return String.fromCodePoint(0xD800 | (code >> 10)) +
2789
String.fromCodePoint(0xDC00 | (code & 0x3FF))
2790
}else{
2791
return String.fromCodePoint(i)
2792
}
2793
}
2795
var _ord = $B.jsstring2codepoint = function(c){
2796
if(c.length == 1){
2797
return c.charCodeAt(0)
2798
}
2799
var code = 0x10000
2800
code += (c.charCodeAt(0) & 0x03FF) << 10
2801
code += (c.charCodeAt(1) & 0x03FF)
2802
return code
2803
}
2804
Sep 5, 2014
2805
})(__BRYTHON__)