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